C语言预处理
By francis_hao May 27,2017
预处理器执行宏替换、条件编译以及包含指定的文件。以#开头的命令行(#前可以有空格)就是预处理的对象,这些命令行的语法独立于语言的其他部分,它们可以出现在任何地方,作用范围是从出现的位置到文件末尾,除非使用显式的取消操作的预处理(undef)。这是一个独立的过程,与之后的编译,汇编和链接相当。
宏定义和扩展
宏定义有两种形式,"[]"中的内容是可选的,其中第二种形式中标识符和形参表之间不能有空格。用引号或嵌套的括号括起来的逗号,不能用于分隔实际参数。
#define 标识符 [实际内容]
#define 标识符(形参表) [实际内容]
宏的取消,两种形式的定义,使用同一种取消的形式:
#undef 标识符
实际内容中,若存在"#"或"##",则会对实际内容进行一些扩展,但他们都不可以嵌套使用。
#的扩展
第一种形式中,"#"无扩展性,包含"#"的实际内容会原样显示。
第二种形式中,"#"后必须也只能跟参数,会把参数转变为可直接使用的字符串,比如,给定的形参若包含""",则转变为"\""。
##的扩展
"##"会将实际内容中"##"前后的空白字符都去掉,也就是拼接。它不可以作用于字符串,也不可以出现在实际内容的开头或结尾。
"##"还有一个特殊的用法,就是和C99标准的__VA_ARGS__配合使用,用在可变参数的宏定义中(第二种形式)。
__VA_ARGS__ can only appear in the expansion of a C99 variadic macro
形如:
#define EE(a, ...) ee(a,##__VA_ARGS__)
其含义是在使用宏EE时,其参数可以只有一个,也可以有多个。
若使用如下形式,则在调用宏EE时,必须给定两个及以上的参数。因为实参和形参必须要对应。
#define EE(a, ...) ee(a,__VA_ARGS__)
若执意不使用"##",也可以使用如下形式,
#define EE(...) ee(__VA_ARGS__)
实例
main.i是main.c进行预处理后的文件。
30行:AA的宏定义中实际内容为空,因此被替换为一空行,此例可使用于程序的调试信息的打印中,使用宏控制是否打印,如:
#ifndef DEBUG |
31行:BB的宏定义是#在第一种形式的使用,无扩展性,因此被原样显示。
32-33行:将参数转换为字符串,若参数中包含""",则进行转义。
35行:"##"在第一种宏定义形式的使用,拼接。其前后不能是字符串,应该只能是数字、字母和下划线。
36行:"##"在第二种宏定义形式的使用,拼接参数。
37-38行:"##"和"__VA_ARGS__"的配合使用。若没有"##",EE的参数只有一个时,EE(a)会变成ee(a,),如下:
错误信息生成
#error [记号序列]
进行预处理到这里的时候会出现错误信息,一般用在条件编译中。
预定义标识符
有些标识符是预定义的,扩展后将生成特定的信息,它们不能被取消定义或重新定义
__LINE__ 包含当前源文件行数的十进制常量
__FILE__ 包含正在被编译的源文件名字的字符串字面值
__DATE__ 包含编译日期的字符串面值,形式为"Mmm dd yyyy"
__TIME__ 包含编译时间的字符串面值,形式为"hh:mm:ss"
__STDC__ 整形常量1,只有在遵循标准的实现中该标识符才被定义为1
本文由 刘英皓 创作,采用 知识共享 署名-非商业性使用-相同方式共享 3.0 中国大陆 许可协议进行许可。欢迎转载,请注明出处:
转载自:http://www.cnblogs.com/yinghao1991/p/6628815.html
参考
[1] K&R C程序设计语言