【问题标题】:Order of evaluation in #if directive: macro expansion vs the "defined" keyword#if 指令中的评估顺序:宏扩展与“定义”关键字
【发布时间】:2021-11-21 18:00:16
【问题描述】:

当 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) 中宏执行。

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

【问题讨论】:

    标签: c language-lawyer c-preprocessor standards c99


    【解决方案1】:

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

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

    在评估之前, 预处理标记列表中将成为控制常量表达式的宏调用被替换(除了那些由defined 一元运算符修改的宏名称),就像在普通文本……

    6.10.1 1 表示#if#elif 的控制表达式应是一个整数常量表达式,它可能还包含表达式defined <i>identifier</i>defined ( <i>identifier</i> ),其中:

    ... evaluate 如果标识符当前被定义为宏名称(也就是说,如果它是预定义的,或者如果它是 #define 预处理指令的主题而没有干预 @ 987654327@ 具有相同主题标识符的指令),如果不是,则为 0。

    因此,按照 6.10.1 4 执行第一次宏替换,然后执行表达式的评估。

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

    …如果令牌defined是作为这个替换过程的结果生成的…,则行为未定义。

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

    …在由于宏扩展和defined一元运算符的所有替换完成后,所有剩余的标识符(包括那些在词法上与关键字相同的标识符)都被替换为pp号0,然后每个预处理标记为转换成代币……

    然后评估控制表达式,您的第 4 步:

    …生成的标记组成控制常量表达式,根据 6.6…的规则进行评估…

    【讨论】:

    • 非常感谢!从您的回答看来,真正的顺序是 2,1,3,4,而不是 2,3,1,4,因为 3 发生“由于 宏扩展已执行定义的一元运算符
    • @koorkevani:是的,看起来是这样。标准中的那个条款组织得很差。
    猜你喜欢
    • 2021-12-09
    • 2011-12-17
    • 1970-01-01
    • 2012-02-03
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多