Preprocessor Operators
一、#
在函数式宏定义中,#
运算符用于创建字符串,#
运算符后面应该跟一个形参(中间可以有空格或Tab),例如:
#define STR(s) # s
STR(hello world)
用cpp
命令预处理之后是"hello␣world"
,自动用"
号把实参括起来成为一个字符串,并且实参中的连续多个空白字符被替换成一个空格。
再比如:
#define STR(s) #s
fputs(STR(strncmp("ab/"c/0d", "abc", '/4"')
== 0) STR(: @/n), s);
预处理之后是fputs("strncmp(/"ab///"c//0d/", /"abc/", '//4/"') == 0" ": @/n", s);
,注意如果实参中包含字符常量或字符串,则宏展开之后字符串的界定符"
要替换成/"
,字符常量或字符串中的/
和"
字符要替换成//
和/"
。
二、#@
在函数式宏定义中,#@
运算符用于创建一个字符,例如:
#define makechar(x) #@x
a = makechar(b);
预处理之后是
a = 'b';
三、##
在宏定义中可以用##
运算符把前后两个预处理Token连接成一个预处理Token,和#
运算符不同,##
运算符不仅限于函数式宏定义,变量式宏定义也可以用。例如:
#define CONCAT(a, b) a##b
CONCAT(con, cat)
预处理之后是concat
。再比如,要定义一个宏展开成两个#
号,可以这样定义:
#define HASH_HASH # ## #
中间的##
是运算符,宏展开时前后两个#
号被这个运算符连接在一起。注意中间的两个空格是不可少的,如果写成####
,会被划分成##
和##
两个Token,而根据定义##
运算符用于连接前后两个预处理Token,不能出现在宏定义的开头或末尾,所以会报错。