【问题标题】:If-directive macro comparisonif 指令宏比较
【发布时间】:2020-07-01 21:04:31
【问题描述】:

为什么满足以下代码中的#if 条件:

#include <iostream>
#define VALUE foo    

int main() {    
#if VALUE == bar
    std::cout << "WORKS!" << std::endl;
#endif // VALUE
}

【问题讨论】:

    标签: c++ c-preprocessor


    【解决方案1】:

    page on cppreference.com 声明:

    在定义和 __has_include 的所有宏扩展和评估之后 (C++17 起) 表达式,任何不是布尔值的标识符 文字被数字 ​0​ 替换(这包括标识符 它们是词法关键字,但不是替代标记,如 and)。

    所以VALUE首先被替换为foo,然后foobar都被替换为0。

    【讨论】:

    • C++98、C++03、C++11和C++14呢?
    • @kelalaka 都是一样的。从 C89 开始就是这样。
    • @kelalaka “自 C++17 起”仅指“and __has_include”部分。在 C++17 之前是一样的,只是省略了那部分。
    【解决方案2】:

    #if 语句中,宏替换后保留的任何标识符(truefalse 除外)都将替换为常量0。所以你的指令变成了

    #if 0 == 0
    

    这是真的。

    【讨论】:

    • 澄清一下,'#define VALUE foo' 定义了符号 'VALUE' 以解析为与符号 'foo' 相同的值,但符号 'foo' 没有意义,所以它将是解释为 0。
    【解决方案3】:

    这是因为 foobar 都没有被赋予任何定义或值 - 所以它们是相同的(即替换为“0”值)。编译器会对此给出警告。

    MSVC 编译器 (Visual Studio 2019) 提供以下功能:

    警告 C4668:'foo' 未定义为预处理器宏,替换 '0' 表示 '#if/#elif'
    警告 C4668:“bar”未定义为预处理器 宏,用 '0' 代替 '#if/#elif'

    所以VALUE 的值是“0”(foo 的默认值)并且bar 也有“0”,所以VALUE == bar 的计算结果为“TRUE”。

    同样,clang-cl 给出以下内容:

    警告:'foo' 未定义,计算结果为 0 [-Wundef]
    警告 : 'bar' 未定义,计算结果为 0 [-Wundef]

    【讨论】:

    • 警告是强制性的还是编译器的特性?
    • @kelalaka 据我所知,没有编译器“警告”是强制性的!即使使用MSVCclang-cl 编译器,也可以禁用此警告(特别是,或通过设置适当的警告“级别”)。
    【解决方案4】:

    要完成你所追求的,试试这个:

    #include <iostream>
    #define DEBUG  
    
    int main() {    
    #ifdef DEBUG
        std::cout << "WORKS!" << std::endl;
    #endif
    }
    

    在这种情况下,您可以通过将“define”更改为“undef”来关闭调试语句。

    #include <iostream>
    #undef DEBUG  
    
    int main() {    
    #ifdef DEBUG
        std::cout << "WORKS!" << std::endl;
    #endif
    }
    

    您可能会发现您的编译器允许您在代码本身之外定义 DEBUG,此时您可以将代码简化为

    #include <iostream>
    
    int main() {    
    #ifdef DEBUG
        std::cout << "WORKS!" << std::endl;
    #endif
    }
    

    然后使用 -DDEBUG=0 等选项调用编译器

    查看 Steve McConnell 中关于防御性编程的章节“代码完成”。

    【讨论】:

      猜你喜欢
      • 2016-11-04
      • 2013-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-05
      • 1970-01-01
      • 2011-07-31
      • 1970-01-01
      相关资源
      最近更新 更多