11

给定

#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。谁能详细解释为什么会这样?

4

3 回答 3

2

我使用 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解决方法)。请参阅为什么我需要宏的双层间接?以及需要将两个标记粘贴在一起的宏应该怎么做?.

于 2012-06-14T17:04:29.213 回答
1

在 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)

该行为是明确定义的,因为所有标记粘贴都会生成有效的预处理器标记,即任何扩展的表达式在任何阶段都应该是有效的标记。

于 2015-03-28T23:00:26.293 回答
0

我不认为 cat 是否真的会连续扩大 2 次。这就是为什么我想知道为什么编译器甚至会产生这样的消息'pasting ")" and "3" does not give a valid preprocessing token'。另外,我不认为内心的猫会首先被扩大。所以,我认为输出将是cat(1,2)3. 这引导我思考编译器将如何解释这一点。

于 2013-02-19T16:37:42.010 回答