宏 # ## #@ 的使用
1. # (stringizing 字符串化操作符)
1.1 作用
将宏定义中的传入参数名转换成用一对双引号括起来参数名字符串(等效地创建字符串字面量)。
1.2 几个注意点
在此之前我们先定义两个宏
#define one_sharp(x) #x
#define showlist(...) puts(#__VA_ARGS__) // __VA_ARGS__ 是可变参数宏
//对于VA_ARGS 参见 参考 1 2
(1) 忽略传入参数名前面和后面的空格.
one_sharp( abcdef ) 展开为字符串 "abcde"
(2) 当传入参数名间存在空格时,编译器将会自动连接各个子字符串,用每个子字符串之间以一个空格连接,忽略剩余空格.
one_sharp( aaa bbb ) 展开为字符串 "aaa bbb"
(3) 如果传入参数是一个用引号括弧的字符串,比如 "aaa", 或者'aaa',或者"a\aa"等,预处理器添加反斜杠以转义单双引号、反斜杠等。
one_sharp(aaa) 展开为字符串 "aaa"
one_sharp("aaa") 展开为字符串 "\"aaa\""
one_sharp("a\aa") 展开为字符串 "\"a\\aa\""
(4) 和 VA_ARGS的结合举例
showlist(); // 展开成 puts("") gcc 支持C++11版本支持
showlist(1, "x", int); // 展开成 puts("1, \"x\", int")
2. ## (token-pasting 符号连接操作符)
2.1 作用
将宏定义的多个形参转换成一个实际参数名。只有一同组成合法记号的记号才可以粘贴:组成更长标识符的标识符、组成数字的数位,或组成 += 的运算符 + 与 = 。
2.2 使用举例
#define two_sharp(x) num#x
...
{
int num666 = 100;
int num = two_sharp(666); // num = num666
// int num = two_sharp(100) 错误 num = num100 找不到 num100
}
3. #@ (charizing 字符化操作符)
3.1 作用
将传入单字符参数名转换成字符,以一对单引用括起来。
3.2 举例
#define charizing(x) #@x
...
{
std::cout << charizing(aaaaaaaaaa) << std::endl;; // 错误
std::cout << charizing(a) << std::endl; // 正确,答应字符 'a'
}
参考资料
[1] 可变参数宏
[2] VA_ARGS 宏的介绍和使用
[3] 文本替换宏
[4] C语言宏定义中的#,##,#@及\符号的作用