给定
#define cat(x,y) x##y
调用cat(a,1)
返回a1
,但cat(cat(1,2),3)
未定义。但是,如果我也定义#define xcat(x,y) cat(x,y)
了,那么结果xcat(xcat(1,2),3)
就是 now 123
。谁能详细解释为什么会这样?
给定
#define cat(x,y) x##y
调用cat(a,1)
返回a1
,但cat(cat(1,2),3)
未定义。但是,如果我也定义#define xcat(x,y) cat(x,y)
了,那么结果xcat(xcat(1,2),3)
就是 now 123
。谁能详细解释为什么会这样?
我使用 GCC 和 Clang 对此进行了测试。
GCC 给出错误:
test.c:6:1: error: pasting ")" and "3" does not give a valid preprocessing token
Clang给出错误:
test.c:6:11: error: pasting formed ')3', an invalid preprocessing token
int b = cat(cat(1,2),3);
似乎正在发生的事情是,编译器cat(1,2)
在展开后立即将结果包装在括号中;所以当你调用cat(1,2)
你的代码时,它真的给了你(12)
. 然后,再次调用cat((12),3)
会导致((12)3)
,这不是一个有效的令牌,这会导致编译错误。
普遍的看法是“在使用标记粘贴运算符 (##) 时,您应该使用两级间接”(即,使用您的xcat
解决方法)。请参阅为什么我需要宏的双层间接?以及需要将两个标记粘贴在一起的宏应该怎么做?.
在 xcat(x,y) 中,x 和 y 与 ## 运算符不相邻,因此它们在被替换之前会进行宏扩展。
所以 x 被标识为 xcat(1,2) 而 y 被标识为 3。但是在替换之前,x 被宏扩展为 cat(1,2),它变成了 1##2,它变成了 12。所以最终, xcat(xcat(1,2),3) 将扩展为 cat(12,3),结果为 123。
这个作品 --> cat(xcat(1,2),3) --> cat(cat(1,2),3) --> cat(12,3)
该行为是明确定义的,因为所有标记粘贴都会生成有效的预处理器标记,即任何扩展的表达式在任何阶段都应该是有效的标记。
我不认为 cat 是否真的会连续扩大 2 次。这就是为什么我想知道为什么编译器甚至会产生这样的消息'pasting ")" and "3" does not give a valid preprocessing token'
。另外,我不认为内心的猫会首先被扩大。所以,我认为输出将是cat(1,2)3
. 这引导我思考编译器将如何解释这一点。