C预处理器使用父宏的右括号

Dav*_*ave 6 c macros c99 c-preprocessor

我有这个代码有效:

#include <stdio.h>
#define A(x) x B
#define B(x) C(x,
#define C(x,y) y x)
int main( void ) {
    printf( A("1") ("2") "3" );
}
Run Code Online (Sandbox Code Playgroud)

它打印132(A宏的点是交换括号中的参数后面的东西与之后的所有东西,直到另一个结束括号)

但如果我在另一个宏中使用它:

#define Z(x) x
printf( Z( A("1") ("2") "3" ) );
Run Code Online (Sandbox Code Playgroud)

我得到编译错误"未终止的函数式宏调用".

我意识到这是因为编译器试图Z独立处理参数,但我需要使用它的右括号作为标记.有没有办法让我在宏中工作?更改调用语法实际上不是一个选项.


ps在我得到任何回复谈论这是多么糟糕的事情之前,请放心:这不是真正的代码.制作用于define在C内部模拟新语言的玩具程序时出现的问题.

zwo*_*wol 3

查看发生情况的最简单方法是稍微更改测试用例。

#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)
Run Code Online (Sandbox Code Playgroud)

预处理到Y(1 3 2]. 这是因为扩张的中间阶段看起来像

Y(1 C(2,3)
Run Code Online (Sandbox Code Playgroud)

此时,C删除了似乎属于Y原文的右括号,并将其替换为右括号。

A(1)(2)3现在,如果位于宏参数内,会发生什么不同的情况?

#define Z(x) x
Z(A(1)(2)3)
Run Code Online (Sandbox Code Playgroud)

由于参数预扫描,类似的中间扩展阶段不是

Z(1 C(2,3)
Run Code Online (Sandbox Code Playgroud)

反而

1 C(2,3
Run Code Online (Sandbox Code Playgroud)

隐藏Z在隐藏的“待扩展”堆栈中。实际上,预处理器强制执行最后一个闭括号所属的文本外观Z,并且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)
Run Code Online (Sandbox Code Playgroud)

预处理到[1 3 2]. 我们使用标记粘贴运算符来防止Z的参数被预扫描,因此我们可以添加一组临时的额外括号供 使用CZZ然后ZZZ再次将它们脱掉。问题是,如果你不粘贴x某些东西,就会出错,所以我们必须在 的定义中添加一个前导下划线,如果 的参数的第一个标记不是可以的,A这将是一个错误Z标记粘贴在下划线之后。

您可能需要考虑使用M4,而不是尝试将其硬塞到 C 预处理器中。