【问题标题】:Rescanning the 'defined' operator after macro expansion: should it work?宏扩展后重新扫描“定义”运算符:它应该工作吗?
【发布时间】:2012-08-07 22:02:50
【问题描述】:

考虑

#define FOOBAR (defined(FOO) || defined(BAR))

#if FOOBAR
/* Do stuff. */
#endif

这应该有效吗?我问是因为显然我的编译器对此没有问题,但 doxygen 内部预处理器认为#if 存在语法错误。我知道我可以解决这个问题

#if defined(FOO) || defined(BAR)
#define FOOBAR 1
#endif
#if FOOBAR
/* Do stuff. */
#endif

【问题讨论】:

    标签: c macros doxygen c-preprocessor


    【解决方案1】:

    来自 C99 规范:

    6.10.1.3

    在评估之前,预处理标记列表中的宏调用将变为 控制常量表达式被替换(除了那些修改的宏名称 由定义的一元运算符),就像在普通文本中一样。如果定义的令牌是 由于此替换过程或使用定义的一元运算符而生成 与宏替换之前的两种指定形式之一不匹配,行为是 未定义。

    因此,如果您使用扩展为 defined 的宏,则结果未定义。

    与 C 规范中的大多数未定义的东西一样,它是未定义的,因为标准之前的实现对它的处理方式不同。

    【讨论】:

    • +1, ... 或者委员会认为编译器实现者处理该特定错误条件的负担太大
    • 来自 GCC 预处理器手册:If the defined operator appears as a result of a macro expansion, the C standard says the behavior is undefined. GNU cpp treats it as a genuine defined operator and evaluates it normally. It will warn wherever your code uses this feature if you use the command-line option -pedantic',因为其他编译器可能会以不同的方式处理它。
    【解决方案2】:

    这听起来像是一个特定于编译器的问题。只要你只是在使用这个编译器,就试试吧——在/*do stuff*/部分放一些代码,看看代码是否被编译。

    【讨论】:

    • 我不太喜欢从“它如何与我的特定编译器一起工作”来推断“它必须如何工作”。这将构成通过实验进行编程,我认为这不是好的工程。由于国际标准中规定了 C 和预处理器的行为,因此我们应该寻找明确的答案。
    猜你喜欢
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 2020-08-01
    • 2021-05-21
    • 1970-01-01
    • 2016-08-08
    • 2010-12-11
    相关资源
    最近更新 更多