参考:https://gcc.gnu.org/onlinedocs/cpp/Macros.html
gcc编译过程一般分为预处理,编译,汇编,连接四个阶段。宏定义在预处理阶段就会被展开。由于预处理器并不认识c预留关键字,所以绝大部分合法的标识符都可以被定义为宏,比如我们可以重定义const的含义。只有define关键字和c++命名操作符不能被重定义。
一。对象形式的宏定义: #define OBJECT_MACRO macro-body
需要特别注意的是宏定义会在调用点原样展开,这和普通函数是不一样的。比如如下代码段:
#define THREE 1+2
std::cout<>>output:5
输出结果是5,和我们的期望不一致。要解决这一点也很容易:
#define THREE (1+2)
std::cout<>>output:6
二。函数形式的宏定义: #define FUNC_MACRO(param1,param2,...,paramn) macro-body
FUNC_MACRO可以像函数一样被调用,参数在调用时将被原样展开。注意宏名字和()之间不能有空格,否则会被当做OJBECT_MACRO展开。
如果宏定义里面出现了同名宏定义,将不会被展开,否则就会无限递归。有时候我们可以利用下这个特性。比如如下代码:
#define printf(fmt, args...) \
printf(fmt, ##args); \
printf(", world\n")
int main(){
printf("hello");
}
>>>output:hello,world
三。将宏函数的参数转化成字符串(#)
如果在宏函数参数前面加上#号,这个参数将不再被展开,而是原样替换成字符串形式。比如如下代码:
#define WARN_IF(EXP) \
do { if (EXP) \
fprintf (stderr, "Warning: " #EXP "\n"); } \
while (0)
WARN_IF (x == 0);
>>>output: Warning:x == 0
四。连接符号(##)
## 可以连接两个符号,如果是宏函数参数的话,宏函数参数将被展开。比如:
#define CONCAT(p1, p2) p1 ## _ ## p2
int CONCAT(hello,world) = 10;
>>>展开: int hello_world = 10;
五。变长参数(...)
宏定义有两种方式处理变长参数:
#define eprintf( ...) printf(__VA_ARGS__)
#define eprintf( arg...) printf( arg)
为了更好的可读性,有时我们会将上面的函数定义为下面这种格式
#define eprintf(format, ...) printf(format, __VA_ARGS__)
#define eprintf(format, arg...) printf(format, arg)
如果这么定义,就会有一个问题如果可变参数列表为空,宏定义展开后就会多一个逗号(,)。
GNU CPP分别给出了一种解决方案,即在可变参数前加上##,代码如下:
#define eprintf(format, ...) printf(format , ##__VA_ARGS__)
#define eprintf(format, arg...) printf(format, ##arg)
六。预定义宏变量:
6.1标准预定义宏变量。
由语言规范规定,所有的编译器都支持。
__FILE__ :当前文件名
__LINE__ :当前行号
__cplusplus :如果是c++编译器,那么这个宏会被定义,否则就是未定义
6.2 通用预定义宏
由GNU C extensions 定义。如果使用GNU C,那么他们的含义是一样的。
__COUNTER__ :单调递增的一个计数器,第一使用值为0,第二次是1 。。。
_GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__
用于检测gnuc的版本,比如如下代码:
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
…
/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200
__GNUG__ :判断是否是GNU C++ (__GNUC__ && __cplusplus)
七。常用宏命令
#define 自定义一个宏
#undef 将一个宏变为未定义
#include 包含一个文件
#if #ifdef #ifndef 判断条件是否满足,或者宏是否定义
#elif #else else判断
#endif 结束if判断