重新扫描宏替换列表以进行替换

时间:2019-01-15 08:01:18

标签: c macros preprocessor

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

  

1替换替换列表中的所有参数后   和#和##处理已经进行,所有地标标记都已预处理   令牌已删除。然后生成的预处理令牌序列   重新扫描,以及所有后续的预处理标记   源文件,以便替换更多的宏名称

因此,在所有###解决之后,我们重新扫描了替换列表。但是第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)的名称(是的,如上定义),它没有被替换(但实际上已被替换,如演示中所示)。 / p>

能否请您澄清一下措辞?我想念什么?

LIVE DEMO

2 个答案:

答案 0 :(得分:7)

要替换的(原始)宏不是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]

答案 1 :(得分:4)

考虑以下简单示例:

#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