参考资料:《C Primer Plus》
1. 字符映射
在C语言预处理的第一步,预处理器会对源代码中的字符作映射处理,若没有特殊要求,这一步一般不会改变源代码的字符。如果程序员需要,字符映射可以将一些扩展的三元字符转换为源字符,例如??=转换为#、??/转换为\等等。之所以这样做是因为不是所有的键盘都能打出#这样的符号,所以通过映射规则的约定来进行处理。
2. ‘\\‘+‘\n‘
预处理器在连续读到反斜线符和换行符时会将这两个字符删除,从而将当前所在的物理行和下一个物理行合并为一个逻辑行。在定义一些比较复杂的宏或字符串时用这个方法可以方便换行阅读,例如
printf("That‘s wonderful!\n");
等价于
printf("That‘s wonderful!\n");
3. 注释
预处理器将注释替换为一个空格字符。
4. 预处理指令
预处理器会将所有以#开头,以换行符结束的字符串作为一条预处理指令,但这个规则不受‘\\‘+‘\n‘组合的影响,因此预处理指令可以多行表示。
4.1 #define-basic
#define指令可以实现字符串替换,前后分为三个部分,分别是#define、宏、替换列表。宏可以分为类对象宏或类函数宏,宏的命名方式和变量标识符一样,可以由字母、数字、下划线组成但首字符不能是数字。如果宏中出现了圆括号,那么将作为类函数宏处理,否则认为是类对象宏。例如
#define PX printf("X is %d.\n",x) #define PR(Z) printf("The result is %d.\n", Z) int main() { int x=0; PX; PR(x); return 0; }
预处理后的结果为
int main() { int x=0; printf("x is %d",x); printf("The result is %d.\n",x); return 0; }
#define支持重定义,代码在前面使用#define定义了一个宏MACRO之后,可以在后面再使用#define更改MACRO的定义。
4.2 #define-##、#、...、__VA_ARGS__
##可以实现标识符的粘合。例如定义#define INT(name) x##name,则INT(1)将转换为x1,之所以这样是因为#define的文本替换是以标识符为单位的,如果直接定义#define INT(name) xname,由于xname与name不是同一个标识符,INT(1)将不能转换为x1。
#可以实现标识符的字符串化,这个功能配合字符串的连接特性可以解决对字符串进行文本替换的问题,之所以这样是因为#define不对字符串的内容进行文本替换。例如#define PSQR(X) printf("The square of X is %d.\n",((X)*(X)));则替换列表中的第一个X将不会被替换。解决的办法是写为#define PSQRprintf("The square of #X " is %d.\n",((X)*(X)));
...和__VA_ARGS__可以实现可变参数宏,例如定义#define PR(...) printf(__VA_ARGS__),则使用PR即可代替printf函数。注意...只能作为最后一个参数,#define FPR(X,...,Y) fprintf(X,__VA_ARGS__,Y)是错误的。
原文:http://www.cnblogs.com/yuqingshan/p/5145854.html