这是我在升级到新版本的编译器时遇到的一个问题:
不必要地使用标记粘贴运算符 ( ##
) 是不可移植的,并且可能会生成不需要的空格、警告或错误。
当令牌粘贴运算符的结果不是有效的预处理器令牌时,令牌粘贴运算符是不必要的并且可能有害。
例如,可以尝试在编译时使用标记粘贴运算符构建字符串文字:
#define STRINGIFY(x) #x
#define PLUS(a, b) STRINGIFY(a##+##b)
#define NS(a, b) STRINGIFY(a##::##b)
printf("%s %s\n", PLUS(1,2), NS(std,vector));
在某些编译器上,这将输出预期结果:
1+2 std::vector
在其他编译器上,这将包括不需要的空格:
1 + 2 std :: vector
相当现代的 GCC 版本(>=3.3 左右)将无法编译此代码:
foo.cpp:16:1: pasting "1" and "+" does not give a valid preprocessing token
foo.cpp:16:1: pasting "+" and "2" does not give a valid preprocessing token
foo.cpp:16:1: pasting "std" and "::" does not give a valid preprocessing token
foo.cpp:16:1: pasting "::" and "vector" does not give a valid preprocessing token
解决方案是在将预处理器标记连接到 C/C++ 运算符时省略标记粘贴运算符:
#define STRINGIFY(x) #x
#define PLUS(a, b) STRINGIFY(a+b)
#define NS(a, b) STRINGIFY(a::b)
printf("%s %s\n", PLUS(1,2), NS(std,vector));
关于连接的GCC CPP 文档章节有更多关于标记粘贴操作符的有用信息。