首页 > 解决方案 > 宏替换列表重新扫描替换

问题描述

我正在阅读关于宏替换的标准 N1570,并误解了6.10.3.4.

1 在替换列表中的所有参数都已被替换并且 # 和 ## 处理已经发生后,所有 placemarker 预处理标记都将被删除。然后重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以替换更多宏名称

所以毕竟解决###我们重新扫描替换列表。但第 2 节规定:

2 如果在替换列表的扫描过程中找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,它不会被替换。

这在我看来很矛盾。那么在重新扫描中可能有什么样的替换?我尝试了以下示例:

#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) 已找到(是的,已在上面定义)它没有被替换(但实际上已被替换,如演示中所示)。

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

现场演示

标签: cmacrospreprocessor

解决方案


被替换的(原始)宏不是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在重新扫描时扩展了一次,而不是再次扩展。

[现场示例]


推荐阅读