c - #if 指令 : macro expansion vs the "defined" keyword 中的评估顺序

标签 c language-lawyer c-preprocessor standards c99

当 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 首先执行,但在 MACRO(defined ID) 宏中。

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

最佳答案

首先执行您的第 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>identifier</i>defined ( <i>identifier</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 token ,它们不一定被评估,因为 6.10.1 4 继续说:

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

然后按照 6.10.1 4 再次执行第 3 步:

… 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…

关于c - #if 指令 : macro expansion vs the "defined" keyword 中的评估顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69382982/

相关文章:

c++ - `friend` 成员函数和属性-gcc vs clang

跨平台访问 C 常量

c++ - 如何定义一个宏来定义一个调用自身的函数?

c - 总线错误,不知道该怎么办

c++ - 如何将 C/C++ 与 python 混合使用?

c - char* 和 int* 之间的区别

c++ - 哪个版本的 C++ 标准允许重用先前由具有 const 或引用成员的类的对象占用的存储空间?

c++ - 关于模板参数推导的看似有缺陷的段落?

c++ - 模板中的预处理器条件

c - 在函数内读取文件,并且内容必须在使用 C 传递的参数中可用