#if 指令中的求值顺序:宏扩展与“define”关键字

koo*_*ani 3 c standards c99 language-lawyer c-preprocessor

当 c 预处理器运行#if/#elif预处理指令时,它会对直接跟随的标记执行 4 个操作:

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

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

从我所做的一些有限测试来看,gcc 似乎根据标记的顺序执行步骤 1 和 2 - 在 中defined MACROdefined首先执行,但在MACRO(defined ID)宏中执行。

标准是否要求这种行为?实现定义的?不明确的?

Eri*_*hil 5

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

\n

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

\n
\n

在求值之前,将替换预处理标记列表中将成为控制常量表达式的宏调用(由defined符修改的宏名称除外),就像普通文本\xe2\x80\xa6 中一样

\n
\n

6.10.1 1 表示 or 的控制表达式#if#elif为整数常量表达式,该表达式还可以包含表达式ordefined identifierdefined ( identifier ),其中:

\n
\n

如果标识符当前被定义为宏名称(即,如果它是预定义的,或者如果它是预处理指令的主题而没有介入),则\xe2\x80\xa6评估为 1#define#undef具有相同主题标识符的干预指令),则为 1,0如果不是。

\n
\n

因此,首先按照 6.10.1 4 执行宏替换,然后执行表达式的求值。

\n

请注意,尽管宏替换首先发生,但如果它生成defined标记,则不一定会计算它们,因为 6.10.1 4 继续说:

\n
\n

\xe2\x80\xa6 如果令牌defined\xe2\x80\xa6 如果此替换过程生成

\n
\n

然后再次按照 6.10.1 4 进行步骤 3:

\n
\n

\xe2\x80\xa6 执行完所有由于宏扩展和一defined元运算符引起的替换后,所有剩余的标识符(包括词法上与关键字相同的标识符)都将替换为 pp-number 0,然后将每个预处理标记转换为标记\xe2\x80\xa6

\n
\n

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

\n
\n

\xe2\x80\xa6 生成的标记组成控制常量表达式,该表达式根据 6.6\xe2\x80\xa6 的规则进行计算

\n
\n