C++ "#"的作用和用法
本系列文章由 @yhl_leo 出品,转载请注明出处。
文章链接: http://blog.csdn.net/yhl_leo/article/details/48879093
1 #和##的作用和用法
C/C++ 的宏中,#的功能是将其后面的宏参数进行字符串化操作,简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。##连接符号由两个井号组成,其功能是在带参数的宏定义中将两个子串联接起来,从而形成一个新的子串。但它不可以是第一个或者最后一个子串。
#include <iostream>
using namespace std;
#define WARN_IF(EXP) if(EXP) cerr << #EXP << endl;
#define paster( n ) cout << "token" << #n << " = " << n << endl;
#define _CONS(a, b) int(a##+##b)
#define _STRI(s) #s
void main()
{
int div = 0;
WARN_IF(div == 0); // prints : div == 0
paster(9); // prints : token9 = 9
cout << _CONS(1, 2) << endl; // prints : 3
cout << _STRI(INT_MAX) << endl; // prints : INT_MAX
}
凡是宏定义里有用#或##的地方宏参数是不会再展开,例如_STRI(INT_MAX)中的INT_MAX就不会被展开为2147483647。如果想要使其中的宏参数展开,则需要多加一层中间转换宏:
#define STRI(s) _STRI(s)
cout << STRI(INT_MAX) << endl; // prints : 2147483647
加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的宏就能得到对应的宏参数。
接下来,我们来了解通过预处理指令创建条件编译参数控制代码编译的一些用法。
2 #include的用法
包含头文件的操作,通常有两种格式:
#include <header-file>
#include "header-file"
<>和""表示编译器在搜索头文件时的顺序不同:
<>表示从系统目录下开始搜索,然后再搜索PATH环境变量所列出的目录,不搜索当前目录""是表示从当前目录开始搜索,然后是系统目录和PATH环境变量所列出的目录。
所以,系统头文件一般用<>,用户自己定义的则可以使用"",加快搜索速度。除此外,写代码多了就会发现,有些头文件之间的相互包含是有隐藏依赖关系的,一定要加以注意。Google C++ Style Guide中也强调使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖:
1 相关文件(优先位置,如
dir2/foo2.h)
2 C系统文件
3 C++ 系统文件
4 其他库的.h文件
5 本项目内.h文件
3 #if,#elif,#else,#endif用法
// structure 1
#if constant_expression
#else
#endif
// structure 2
#if constant_expression
#elif constant_expression
#endif
这里的结构跟常见的if...else和if...else if...else语句类似,当#if后的条件为非零(true)时,编译#if和#else或#elif之间的代码,否则编译#else和#endif之间的代码(或者判断#elif后的条件是否非零(true),决定是否编译#elif和#endif之间的代码)。
#if 1
cout << "Hello world!" << endl;
#else
cout << "Nice to meet you!" << endl;
#endif
// prints : Hello world!
#if 1
cout << "Hello world!" << endl;
#elif 1
cout << "Nice to meet you!" << endl;
#endif
// prints: Hello world!
// Nice to meet you!
4 #define,#undef,#ifdef,#ifndef用法
#define是大家都常见的宏定义方法,用法结构为:
// #define identifier replacement-code
#define PI 3.1415926
#define ADD(x,y) (x + y)
#undef顾名思义,就是从该处取消前面已经定义的宏,如果标识符当前没有被定义称为一个宏名称,就会忽略该指令:
// #undef identifier
#undef PI
#ifdef和#ifndef 含义相反,前者含义为如果定义了该宏,则编译相应代码;后者则为如果没有定义该宏,则编译相应代码。通用结构为:
/*
* #ifdef identifier
* #else or #elif
* #endif
**/
#define DEBUG
#ifdef DEBUG
cout << "This is a debug message." << endl;
#endif
// prints : This is a debug message.
/*
* #ifndef identifier
* #else or #elif
* #endif
**/
#ifndef DEBUG
cout << "This is a debug message." << endl;
#endif
// prints nothing
在编程时,为了避免头文件重定义,经常使用的就是#define配合条件编译解决:
#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
// ...
class MyHeaderFile
{
// ....
};
#endif // MY_HEADER_FILE_H
除此以外,还有#pragma once的用法,只要在头文件的最开始加入这条指令就能够保证头文件被编译一次。(在所有的预处理指令中,#pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作,本文不多讲述。)
5 #line用法
#line命令是用于更改__LINE__ 和 __FILE__变量的值。__FILE__和__LINE__描述被读取的当前文件和所在行数。
// #line line-number filename
int main()
{
#line 10 "main.cpp"
cout << __FILE__ << " " << __LINE__ << endl;
}
// prints : main.cpp 10
6 #error用法
#error会直接导致程序停止编译并输出指定的错误信息:
// #error message
#ifndef VERSION
#error Version number not specified.
#endif
// The compiler will halt compiling and return with the specified error message:
// fatal error C1189: #error : Version number not specified.
C++ "#"的作用和用法的更多相关文章
- serialVersionUID, ObjectInputStream与ObjectOutputStream类,Serializable接口,serialVersionUID的作用和用法
ObjectInputStream与ObjectOutputStream类所读写的对象必须实现Serializable接口,对象中的transient和static类型成员变量不会被读取和写入 Ser ...
- Oracle函数over(),rank()over()作用及用法--分区(分组)求和& 不连续/连续排名
(1) 函数: over()的作用及用法: -- 分区(分组)求和. RANK ( ) OVER ( [query_partition_clause] order_by_clause )D ...
- Linq中关键字的作用及用法
Linq中关键字的作用及用法 1.All:确定序列中的所有元素是否都满足条件.如果源序列中的每个元素都通过指定谓词中的测试,或者序列为空,则为 true:否则为 false. Demo: 此示例使用 ...
- JSP九大内置对象的作用和用法总结?
JSP九大内置对象的作用和用法总结? 1.request对象javax.servlet.http.HttpServletRequest request对象代表了客户端的请求信息,主要用于接受通过HTT ...
- (转载)MySQL数据类型中DECIMAL的作用和用法
(转载)http://database.51cto.com/art/201005/201651.htm 在MySQL数据类型中,例如INT,FLOAT,DOUBLE,CHAR,DECIMAL等,它们都 ...
- PreTranslateMessage作用和用法
PreTranslateMessage作用和用法 PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗体的消息都要通过这里,比較经常使用, ...
- ViewHolder的作用和用法
一直都看别人用ViewHolder,自己也用过,却不知道它的作用是什么?但知道肯定很有用,而且现在android studio应该有直接生产Viewholder的插件, 不过博主我是个新手,就没尝试去 ...
- Oracle分析函数及常用函数: over(),rank()over()作用及用法--分区(分组)求和& 不连续/连续排名
(1) 函数: over()的作用及用法: -- 分区(分组)求和. sum() over( partition by column1 order by column2 )主要用来对某个字 ...
- og标签对SEO的作用及用法
meta property=og标签对SEO的作用及用法,如果你仔细观察会发现本站点<head>代码中有一段:"property="og:image"这段代码 ...
- PHP strip_tags() 函数的作用和用法
strip_tags()函数可以轻松实现从字符串中去除 HTML 和 PHP 标记. 使用方法: trip_tags ( string $str [, string $allowable_tags ] ...
随机推荐
- 简单总结static、final、this关键字的使用
在最近看书的过程中,常常遇到static.final.this这三个关键字,不是很明白它们的使用,查阅资料结合实例做了如下总结: 一.static——无需创建对象就可以调用(方法.属性). 1.静态变 ...
- VS2013 EF6连接MySql
1.安装mysql server下载地址 http://cdn.mysql.com/Downloads/MySQL-5.6/mysql-5.6.21-winx64.zip 2.安装MySql的VS插件 ...
- 【BZOJ 2351】 Matrix
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2351 [算法] 哈希 [代码] #include<bits/stdc++.h& ...
- Serializable-源码分析
package java.io; public interface Serializable { } 代码很简单,功能也很简单,对象通过这个接口来实现序列化和反序列的.下面来看看小例子. import ...
- ffmpeg实现
最近做一个小项目,要在线播放录制的 MP4 视频,想开源的 flash player 或 html 5 可以播放.可,虽然 MP4 是 H.264 编码,但就是播放不了.可能是封装方式(PS 方式)不 ...
- MyEclipse设置默认注释的格式
首先选菜单windows-->preferenceJava-->Code Style-->Code Templates code-->new Java files 然后选中点编 ...
- Spring《七》ApplicationContext
1.国际化支持 getMessage()提供了国际化支持. Bean中必须定义为messageSource. <bean id="messageSource" class=& ...
- hiho一下 第173周
题目1 : A Game 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi and Little Ho are playing a game. Ther ...
- React 16 服务端渲染的新特性
React 16 服务端渲染的新特性 React 16 中关于服务端渲染的新特性 快速介绍React 16 服务端渲染的新特性,包括数组.性能.流等 React 16 终于来了!
- 使用DbVisualizer变量
变量可用于构建参数化SQL语句,并让DbVisualizer在执行SQL时提示您输入值.如果您重复执行相同的SQL,只是希望在同一个SQL语句中传递新数据,这很方便. 变量语法 变量格式支持设置默认值 ...