“#”(stringizing)是字符串化操作符。其作用是:将宏定义中的传入参数名转换成用一对双引号括起来参数名字符串。
其只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。
如:
运行结果为:
【注意】预处理器对于对空格的处理逻辑如下:
忽略传入参数名前面和后面的空格。
如:str=FUNC1( abc ); 将会被扩展成 str="abc";
当传入参数名间存在空格时,编译器将会自动连接各个子字符串,用每个子字符串中只以一个空格连接,忽略其中多余一个的空格。
如:str=exapme( abc def); 将会被扩展成 str="abc def";
“##”的名称是(token-pasting)符号连接操作符,其作用是将两个宏字符串拼接在一起。
【问题】两个宏字符串拼在一起有什么用处?
其中一个用处就是能够为变量提供统一的前后缀,例如想要给x,y,z变量都加上前缀“a_”,直接写在代码里,会重复很多次。 而且哪一天需要改前缀的名称时,需要修改很多处,此时可以使用##来给变量自动加上前缀,具体代码如下所示。
【注意】
1.当用##连接形参时,##前后的空格可有可无。
2.连接后的实际参数名,必须为实际存在的参数名或是编译器已知的宏定义。
宏定义有时候不一定会在c文件中起作用,如下面的例子所示。 main.c依赖a.h和a.c,而a.h又依赖b.h,所以我们自然而然的认为在main.c里包含a.h之前加入某一个宏,它能够在a.h和b.h都生效。 在头文件中,这是没有问题的,但是对于b.c文件,就不管用了(实际工作碰到的例子),因为b.h和b.c在编译的时候他们并不依赖其他模块,所以有可能b模块比main编译的时刻还要早(编译成obj文件),另外,如果仅仅是修改了宏,a.h和a.c的内容不会改变,那么a.o根本就不会重新发生编译。
解决方法,使用编译工具的宏定义工具,例如cmake的