【问题标题】:Why is the macro-name not painted blue?为什么宏名称没有涂成蓝色?
【发布时间】:2020-10-22 02:26:46
【问题描述】:

假设我有以下两个宏定义:

#define foo(X) 1 bar
#define bar(X) 2 foo

为什么foo(X)(Y)(Z) 会扩展为1 2 1 bar

根据 C99 标准 6.10.3.4 重新扫描和进一步替换

如果在此扫描期间找到要替换的宏的名称 替换列表(不包括源文件的其余部分 预处理令牌),它不会被替换。此外,如果任何嵌套 替换遇到被替换的宏的名称,它不是 更换。这些不可替换的宏名称预处理标记不是 更长的时间可用于进一步更换,即使它们稍后再更换 在该宏名称预处理标记的上下文中(重新)检查 否则会被替换。

所以这些标记的翻译方式似乎是以下序列

foo(X)(Y)(Z)
1 bar(Y)(Z)
1 2 foo(Z)
1 2 1 bar

显然foo 的第二个宏调用没有被涂成蓝色。我有点不确定为什么会这样。它不是由调用bar 引起的替换的一部分吗?这将使它成为第一次调用foo 的替换的嵌套替换。

我只能争辩说,这些扩展的工作方式是导致foobar 的宏调用的标记部分位于嵌套替换中,即宏的名称在其中,部分在外部替换,即括号部分在替换之外。

也许我完全误解了嵌套替换的含义。

谁能帮我解释一下。

【问题讨论】:

    标签: c c-preprocessor c99


    【解决方案1】:

    这里有 2 个替换阶段。首先发生在参数替换期间,它与文件的其余部分隔离发生:

    6.10.3.1 参数替换

    1. 在确定调用类函数宏的参数后,参数 发生替换。替换列表中的参数,除非 前面有 # 或 ## 预处理标记或后跟 ## 预处理令牌(见下文),由相应的替换 在其中包含的所有宏都已展开之后的参数。 之前 被替换,每个参数的预处理标记完全是 宏被替换,好像它们形成了预处理文件的其余部分; 没有其他可用的预处理令牌。

    第二阶段,重新扫描,发生在宏和它的参数被扩展之后:

    6.10.3.4 重新扫描和进一步替换

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

    您所指的段落仅适用于第一阶段,参数替换:

    1. 如果找到被替换的宏的名称 在替换列表的扫描期间(不包括其余的 源文件的预处理标记),它不会被替换。 ...

    由于您的宏 foobar 不使用它们的参数,您只能看到重新扫描阶段的效果。

    【讨论】:

    • 感谢您的回复,但我认为我不同意或理解您的推论。我真的认为“此扫描”是指替换第 1 点中描述的替换列表中的参数。正如您在回答中引用的那样。第1点描述了替换列表中扩展参数的扫描和替换阶段。第 2 点紧跟在第 1 点之后。因此“此扫描”必须与前面第 1 点中描述的替换列表扫描相识别。
    • @ArisKoning foo 的替换列表(如:“替换列表中的所有参数都被替换后”)为:1 bar。该替换列表不包含bar 调用。 foo 被涂成蓝色,而 6.10.3.4p2(“替换列表扫描”,另请注意“不包括源文件的其余预处理标记”)发生。然后,它完成了,foo 未绘制。然后你有1 bar (Y)(Z)那么你有bar (Y),这是对bar的调用;该调用不是 foo 重新扫描和替换的一部分。
    • 为了清楚起见,回顾一下#define foo(X) 1 bar(X)#define bar(x) 2 foo(X)#define A 7 的案例。使用foo(A) 调用。现在foo 的替换列表是1 bar(X)。发生参数替换(a.s.),你得到1 bar(7)。然后将foo 涂成蓝色,然后重新扫描并进行进一步替换(r.a.f.r.)。 bar(7) 现在是一个调用,它是嵌套的。作为。的bar 产生2 foo(7)。然后 r.a.f.r.酒吧发生; bar 现在已绘制。现在你只得到2 foo(7),因为foo 仍然被绘制。所以结果是1 2 foo(7)。然后bar 未绘制,然后foo
    • 在参数替换后的扫描过程中,bar 在展开的替换列表内遇到,而括号内的部分 (Y) 在此替换列表之外。 bar(Y) 的宏扩展显然没有被 clang 和 gcc 预处理器解释为嵌套替换。那么嵌套替换的定义是什么?这在标准中找不到。这就是标准变得模棱两可的地方。它应该指定标记序列与扩展替换列表重叠但不是严格子序列的宏调用会发生什么。
    • 嵌套有共同的意思。有一个 r.a.f.r.步骤,在此期间进行某些评估。该评估可以调用宏。此类调用“重新开始”,但仍在评估 r.a.f.r. 的过程中;因此它们是“嵌套的”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多