宏替换列表重新扫描替换

Macro replacement list rescanning for replacement

我正在阅读有关宏替换的标准 N1570,但误解了 6.10.3.4 中的一些措辞。

1 After all parameters in the replacement list have been substituted and # and ## processing has taken place, all placemarker preprocessing tokens are removed. The resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace

所以在 ### 都解决后,我们重新扫描替换列表。但第 2 节指定:

2 If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file’s preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced.

我觉得很矛盾。那么在重新扫描中可能进行什么样的替换呢?我尝试了以下示例:

#define FOOBAR(a, b) printf(#a #b)

#define INVOKE(a, b) a##b(a, b)

int main() {
    INVOKE(FOO, BAR); //expands to printf("FOO" "BAR")
}

因此 INVOKE(FOO, BAR) 在替换 ## 后扩展为 FOOBAR(FOO, BAR)。然后重新扫描替换列表FOOBAR(FOO, BAR)。但是 2. 部分指定被替换的宏的名称 (FOOBAR) 被发现(是的,在上面定义)它没有被替换(但实际上被替换了,如演示中所示)。

你能澄清一下这个措辞吗?我错过了什么?

LIVE DEMO

被替换的(原始)宏不是 FOOBAR,而是 INVOKE。当您展开 INVOKE 并找到 FOOBAR 时,您会正常展开 FOOBAR。但是如果展开INVOKE的时候已经找到了INVOKE,就不会再展开了。

让我们看下面的代码:

#define FOOBAR(a, b) printf(#a #b)

#define INVOKE(a, b) e1 a##b(a, b)

int main() {
    INVOKE(INV, OKE);
}

我将 e1 添加到 INVOKE 的扩展中,以便能够可视化发生了多少次扩展。预处理main的结果是:

e1 INVOKE(INV, OKE);

这证明 INVOKE 被扩展了一次,然后在重新扫描时没有再次扩展。

[Live example]

考虑以下简单示例:

#include<stdio.h>

const int FOO = 42;

#define FOO (42 + FOO) 

int main()
{
   printf("%d", FOO);
}

此处输出为 84。

printf 将扩展为:

printf("%d", 42 + 42);

这意味着当宏FOO展开时,当找到第二个FOO时展开就会停止。它不会进一步扩展。否则,你将以无休止的递归结束,结果是:42 + (42 + (42 + (42 + ....)

现场演示 here