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
#define debug_print(fmt, ...)
#else
#define debug_print(fmt, ...) printf(fmt,##__VA_ARGS__)
#endif

 

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程序设计语言

posted on 2017-03-27 21:10  刘英皓  阅读(1271)  评论(0编辑  收藏  举报