1. #
是字符串化操作符。它的作用是将宏参数转换成字符串
2. ##
是标记粘贴操作符。它的作用是将两个标记连接起来形成一个新的标记
#define TEST1(a) #a
#define TEST2(a) b##a/***********************************************************/
举例:TEST1(hello) 会被替换为 "hello" 字符串TEST2(hello)会被替换为 bhello, 编译过程中会将bhello当作一个变量
/***********************************************************/
字符串拼接
#define HELLO_WORLD "Hello, " "World!"/***********************************************************/
在HELLO_WORLD中,"Hello, " "World!" 会被连接为 "Hello, World!"HELLO_WORLD 会被替换为 "Hello, World!" 字符串
/***********************************************************/
利用#将宏参数转换成字符串的特性可以完成字符串的拼接:
#defien HELLO(a) "hello"#a/***********************************************************/
举例:
HELLO(bye)会被替换为 "hellobye" 字符串HELLO(bye) 被转换为 "hello""bye" 再转换为 "hellobye"/***********************************************************/
重要事项
1. 在C或C++中的宏定义中,#运算符(被称为“字符串化”)只能用于宏参数。这意味着#必须直接跟在参数名称后面,不能有任何东西介于#和参数名称之间。换句话说,你不能在#和参数名之间添加任何非空白的字符。
错误案例:
#define STRING(a) nihao##a
#define TOSTRING(a) #STRING(a)/*********************************************/这个案例似乎想将nihao与参数a进行拼接并转换为字符串
但是#与参数之间不能存在其他字符,因此#操作符在此处其实是失效的
执行TOSTRING(a)等价于执行了STRING(a)
TOSTRING(a) 会被替换为 nihaoa, 编译过程中会将nihaoa当作一个变量。因为#操作符的无效/*********************************************/
2. ##符号两侧的空格会被忽略
#define CONCAT1(a,b) a##b#define CONCAT2(a,b) a ## b/****************************************/CONCAT1(a,b) 与 CONCAT2(a,b) 都会被替换为ab变量/****************************************/
3. ##
运算符还有一个特殊的作用,就是当它跟在一个逗号后面,并且其后面继续跟随如##__VA_ARGS__
的类型参数为空时,预处理器就会消除这个逗号
_VA_ARGS__
是C语言预处理器定义的一个指示符,它代表了可变参数的列表。它主要用于宏的定义中,当你需要定义一个接收可变数量参数的宏时。
#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__ )/*****************************************************/上述宏如果被传递一个参数,例如 FOO( "Hello, world!" ),
则__VA_ARGS__为空,此时##会去掉前面的逗号,从而避免了语法错误。/******************************************************/
#__VA_ARGS__将会把__VA_ARGS__转化为字符串。
#define DEBUG(...) ##__VA_ARGS__/*********************************************/DEBUG(ni, hao, a) 会被替换为 "ni, hao, a" 字符串/**********************************************/