查看发生情况的最简单方法是稍微更改测试用例。
#define A(x) x B
#define B(x) C(x,
#define C(x,y) y x] /* note close square bracket instead of close paren */
Y(A(1)(2)3)
预处理到Y(1 3 2]
。这是因为扩张的中间阶段看起来像
Y(1 C(2,3)
此时C
是近亲似乎属于Y
原文中并将其替换为右括号。
现在,如果A(1)(2)3
是在宏参数里面吗?
#define Z(x) x
Z(A(1)(2)3)
因为参数预扫描 http://gcc.gnu.org/onlinedocs/gcc-4.8.0/cpp/Argument-Prescan.html#Argument-Prescan,类似的扩张中间阶段是not
Z(1 C(2,3)
反而
1 C(2,3
with Z
隐藏在隐藏的“待扩展”堆栈中。预处理器实际上是执行最后一个闭括号所属的文本外观Z
, and C
是不允许借用的。
我能想到的实现最初目标的侵入性最小的方法是
#define _A(x) x B
#define B(x) C(x,
#define C(x,y) y x)
#define Z(x) ZZ((_##x))
#define ZZ(x) ZZZ x
#define ZZZ(x) [x]
Z(A(1)(2)3)
预处理到[1 3 2]
。我们使用令牌粘贴运算符来防止Z
的参数被预扫描,所以我们可以添加一组临时的额外括号供使用C
. ZZ
and ZZZ
然后再次将它们脱掉。问题是如果不粘贴就会出错x
with 某物,所以我们必须在定义中添加一个前导下划线A
,如果第一个标记为Z
的参数永远不能在下划线之后进行标记粘贴。
您可能需要考虑使用M4 https://www.gnu.org/software/m4/而不是试图将其硬塞到 C 预处理器中。