嵌套调用中##运算符的行为

sha*_*kim 4 c c-preprocessor

我正在读一本关于C编程语言的书,我发现:

#define cat(x,y) x##y
#define xcat(x,y) cat(x,y)
Run Code Online (Sandbox Code Playgroud)

调用cat(cat(1,2),3)产生错误,而调用xcat(xcat(1,2),3)产生预期结果123.

两者的工作方式有何不同?

hac*_*cks 5

替换列表依赖的宏##通常不能以嵌套方式调用.
cat(cat(1,2),3)不会以正常的方式扩张,cat(1,2)屈服12然后cat(12, 3)屈服123.替换列表
中之前或之后的宏参数##在替换时不会扩展.

6.10.3.1参数替换

1在识别出类似函数宏的调用参数之后,进行参数替换.在替换列表中的参数,除非前面有一个###预处理记号或后跟一个##预处理标记(见下文),由对应的参数替换后其中所含的所有宏已经扩大.在被替换之前,每个参数的预处理标记都被完全宏替换,好像它们形成了预处理文件的其余部分; 没有其他预处理令牌可用.

因此,cat(cat(1,2),3)扩展为cat(1,2)3,无法进一步扩展,因为没有名称的宏cat(1,2)3.

如果

#define xcat(x,y) cat(x,y)  
Run Code Online (Sandbox Code Playgroud)

写作xcat(xcat(1,2),3)会奏效.随着预处理器扩展外部调用xcat,它也将扩展xcat(1,2); 区别在于xcat替换列表不再包含##.

xcat(xcat(1,2),3) ==> cat(12, 3) ==> 12##3 ==> 123
Run Code Online (Sandbox Code Playgroud)

  • @haccks:你必须结合6.10.3.3阅读6.10.3.1.`cat(cat(1,2),3)`首先被`cat(1,2)## 3`替换(参数被字面替换,而不是宏扩展).然后`##`尝试将`)与`3`连接起来.但是,`)3`不是一个有效的预处理标记,所以UB是6.10.3.3/3(第8行).我重读了相关问题以及Jayesh发掘的问题,我认为克里斯多德的答案最接近,但你的答案就是到达那里:) (2认同)