1.1:#
在宏体中,如果宏参数前加个#,那么在宏体扩展的时候,宏参数会被直接被扩展成字符串的形式,而不在乎宏参数在上文中的值。
1.2:##
##是个粘合剂,先分隔,然后进行强制连接。当两边参数有变量时,将前后两部分粘合起来,“组成变量名”;若两边参数都是常数,则输出粘合的常数结果。
若两边都是字符串,会报“does not give a valid preprocessing token”错:
关于g++报错这两行:
cout < <NUM("1","2","3") < <endl; --> "1""2""3"
cout < <STR("aa","bb","cc") < <endl; --> "aa""bb""cc"
这种情况下完全没必要使用##,直接写成"1""2""3"就是一个字符串。
g++大概是对这种行为很不理解,认为使用##应该产生一个新的token才合理,
而VS和VC就觉得无所谓。
http://topic.csdn.net/u/20071210/15/0fc45077-21fd-4b7b-a0fa-d6abaea27503.html
1.3:可变宏:… 和_VA_ARGS
//两种写法同效果
#define DBG(fmt,...) \
do {\
debug(number++, fmt, __VA_ARGS__);\
} while(0)
#define DBG(fmt, args...) \
do {\
debug(number++, fmt, ##args);\
} while(0)
1.4:注意事项
在单一的宏定义中,最多可以出现一次“#”或“##”预处理操作符。如果没有指定与“#”或“##”预处理操作符相关的计算次序,则会产生问题。为避免该问题,在单一的宏定义中只能使用其中一种操作符(即,一份“#”或一个“##”,或都不用)。
1.4:常用宏定义
防止一个头文件被重复包含
#ifndef BODYDEF_H#define BODYDEF_H
//头文件内容
#endif
得到一个field在结构体(struct)中的偏移量
#define OFFSETOF( type, field ) ( (size_t) &(( type *) 0)-> field )
返回数组元素的个数
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
防止溢出的一个方法
#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
判断字符是不是16进值的数字
#define HEXCHK( c ) ( ((c) >= ''0'' && (c) <= ''9'') ||((c) >= ''A'' && (c) <= ''F'') ||((c) >= ''a''&& (c) <= ''f'') )
将一个字母转换为大写
#define UPCASE( c ) ( ((c) >= ''a'' && (c) <= ''z'') ? ((c) - 0x20) : (c) )
1.5 ANSI C标准宏
__func__ //在源代码中插入当前函数名行号 __LINE__ // 在源代码中插入当前源代码行号 __FILE__ // 在源文件中插入当前源文件名 __DATE__ // 在源文件中插入当前的编译日期 __TIME__ // 在源文件中插入当前编译时间 __STDC__ // 当要求程序严格遵循ANSI C标准时该标识被赋值为1 __cplusplus // 当编写C++程序时该标识符被定义 _WIN32 // 在程序运行在windows系统上被定义位1 linux // 在程序运行在linux系统上被定义位1 __x86_64__ // 在程序运行在64位系统上被定义位1 __i386__ // 在程序运行在32位系统上被定义位1 __VA_ARGS__ // 是一个可变参数的宏,在新C99规范中新增, // 目前似乎gcc和VC6.0之后的都支持(VC6.0的编译器不支持)。 // 宏前面加上##的作用在于,可以接受参数为0个或者多个
小练习:
#include <stdio.h>
#define Conn(x, y) x##y //拼接出上文中的变量,若结果变量不存在会报错
#define ToString(x) #x //将入参而不是入参值转化为字符串
int main () {
int k = Conn(5, 1); //粘合常量
printf("k = %d\n", k);
int i1, j;
for(i1 = 1; i1 < 10 ; i1++) {
j = Conn(i, 1)++; //粘合变量
printf("number %d:the sum of %s is: %d\n", i1, ToString(j*10+i1), j*10+i1);
}
printf("well done!\n");
return 0;
}
输出:
k = 51
number 2:the sum of j*10+i1 is: 12
number 4:the sum of j*10+i1 is: 34
number 6:the sum of j*10+i1 is: 56
number 8:the sum of j*10+i1 is: 78
number 10:the sum of j*10+i1 is: 100
well done!