如何在 concatenate-stringify 级联中延迟宏替换

How to defer a macro substitution in a concatenate-stringify cascade

这是 的后续问题(也更接近手头的实际问题)。

如果我有以下情况:

#include <stdio.h>

#define FOO_ONE 12
#define FOO_TWO 34
#define BAR_ONE 56
#define BAR_TWO 78

#define FOO 99

#define STRINGIFY(mac) #mac
#define CONCAT(mac1, mac2) STRINGIFY(mac1) STRINGIFY(mac2)
#define MAKE_MAC(mac) CONCAT(mac##_ONE, mac##_TWO)

#define PRINT(mac) printf(#mac ": " MAKE_MAC(mac) "\n")

void main(int argc, char *argv[])
{
    PRINT(FOO);
    PRINT(BAR);
}

可以看出,字符串化的、串联的宏然后在 printf() 语句中被替换,该语句本身在宏中。

因为 FOO 被定义(如 99),它恰好在与 _ONE_TWO 连接之前展开,有效地创建了标记 99_ONE99_TWO.

这个程序输出:

FOO: 99_ONE99_TWO
BAR: 5678

如何推迟 FOO 宏的扩展(有效地完全消除它,以获得所需的输出:

FOO: 1234
BAR: 5678

注意:假设 PRINT() 宏签名无法更改(即无法添加参数等)。但是它的实现可以改变。此外,FOOFOO_*BAR_* 定义也无法修改。

如果每次使用 FOO 时你都可以做一些事情,你可以先取消定义宏,以便它根据需要扩展,然后重新定义它,如

#undef FOO
PRINT(FOO);
#define FOO 99

在这种情况下它将扩展到

printf("FOO" ": " "12" "34" "\n");

printf("BAR" ": " "56" "78" "\n");

打印你想要的。

How can I defer the expansion of the FOO macro ... NOTE: assume the PRINT() macro signature cannot be changed (i.e., can't add a parameter, etc.)

你不能。

宏展开要经过一系列步骤:

  • 参数替换
  • 粘贴和字符串化不分先后
  • 重新扫描并进一步替换

参数替换发生在您的参数中;在调用 PRINT(FOO)FOO 的情况下;这是第一步。当你甚至让预处理器识别出你的替换列表中的某些东西是一个宏时,你已经很久没有参数替换了。

参数替换的规则是,如果您的替换列表中提到了任何参数,并且这些参数既没有被字符串化也没有被粘贴,那么相应的参数将被完全评估,并且这些参数的提及被替换为结果。在这种情况下,PRINT(FOO),在参数替换之后,结果是替换列表:

printf(#mac ": " MAKE_MAC(99) "\n")

同样,MAKE_MAC 的定义无关紧要;在重新扫描和进一步替换之前,它甚至不会被识别为宏。

现在,在没有您的限制的情况下,您可以推迟 FOO 展开...,方法是向 PRINT 添加第二个参数并粘贴到它(这会使它失去 a.s. 的资格,到重新扫描和替换出现时,它会调用你的下一个宏)。但是由于你的限制,你是 DOA。

FOO 实际扩展到 99 发生在 PRINT 扩展的那一刻,并且在它的主体被再次重新扫描之前。 ANSI标准的相关部分是:

6.10.3.1 Argument substitution

1 After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

在你的情况下,你可以通过替换

来避免扩展 FOO(在 mac 内)
#define PRINT(mac) printf(#mac ": " MAKE_MAC(mac) "\n")

#define PRINT(mac) printf(#mac ": " CONCAT(mac##_ONE, mac##_TWO) "\n")