#if 指令中的评估顺序:宏扩展与 "defined" 关键字

Order of evaluation in #if directive: macro expansion vs the "defined" keyword

当 c 预处理器运行 #if/#elif 预处理指令时,它对紧跟在后面的标记执行 4 个操作:

  1. 如果定义了 {identifier},则将每次出现的 defined {identifier} 替换为 1,否则为 0
  2. 调用所有宏。
  3. 0 替换每个剩余的标识符。
  4. 将结果解析并评估为 constant-expression

现在,从标准 (c99, 6.10.1) 可以很清楚地看出,步骤 3 和 4 实际上按此顺序发生,并且在 1 和 2 完成之后。但是我找不到任何关于 1 和 2 顺序的说明。

从我所做的一些有限测试来看,gcc 似乎根据标记的顺序执行步骤 1 和 2 - 在 defined MACRO 中,defined 首先执行,但在 [=21] =] 宏确实如此。

标准是否要求这种行为?实现定义?未定义?

首先执行您的第 2 步。顺序为第2、1、3、4步:

C 2018 6.10.1 4 说 [强调我的]:

Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary operator), just as in normal text…

6.10.1 1 表示 #if#elif 的控制表达式应该是一个整数常量表达式,它可以另外包含表达式 defined <i>标识符</i>已定义(<i>标识符</i>)其中:

evaluate to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has been the subject of a #define preprocessing directive without an intervening #undef directive with the same subject identifier), 0 if it is not.

因此,根据 6.10.1 4,首先执行宏替换,然后执行表达式的计算。

请注意,尽管宏替换首先发生,但如果它生成 defined 个标记,则不一定会对其进行评估,因为 6.10.1 4 继续说:

… If the token defined is generated as a result of this replacement process…, the behavior is undefined.

然后你的第 3 步发生,再次根据 6.10.1 4:

… After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number 0, and then each preprocessing token is converted into a token…

然后计算控制表达式,你的第 4 步:

… The resulting tokens compose the controlling constant expression which is evaluated according to the rules of 6.6…