首页 文章

为什么在C布尔宏中#define为TRUE(1 == 1)而不是简单为1?

提问于
浏览
159

我见过C中的定义

#define TRUE (1==1)
#define FALSE (!TRUE)

这有必要吗?简单地将TRUE定义为1,将FALSE定义为0有什么好处?

8 回答

  • 50

    如果编译器支持,此方法将使用实际 boolean 类型(并解析为 truefalse ) . (具体来说,C)

    但是,最好检查C是否正在使用(通过 __cplusplus 宏)并实际使用 truefalse .

    在C编译器中,这相当于 01 .
    (请注意,删除括号会因操作顺序而中断)

  • 18

    答案是便携性 . TRUEFALSE 的数值并不重要 . 重要的是像 if (1 < 2) 之类的语句求值为 if (TRUE)if (1 > 2) 之类的语句求值为 if (FALSE) .

    当然,在C中, (1 < 2) 评估为 1(1 > 2) 评估为 0 ,正如其他人所说,就编译器而言,没有实际区别 . 但是通过让编译器根据自己的规则定义 TRUEFALSE ,您可以保证程序和任何其他库的一致性(假设其他库遵循C标准......你会感到惊讶) .


    Some History
    一些BASIC将 FALSE 定义为 0 ,将 TRUE 定义为 -1 . 像许多现代语言一样,他们将任何非零值解释为 TRUE ,但他们评估的布尔表达式为 -1 . 他们的 NOT 操作是通过添加1并翻转符号来实现的,因为以这种方式执行它是有效的 . 所以'NOT x'成了 -(x+1) . 这样做的副作用是像 5 这样的值计算为 TRUE ,但 NOT 5 的计算结果为 -6 ,这也是 TRUE !找到这种bug并不好玩 .

    Best Practices
    鉴于事实上的规则将零解释为 FALSE 并且任何非零值被解释为 TRUE ,您应该 never compare boolean-looking expressions to TRUE or FALSE . 例子:

    if (thisValue == FALSE)  // Don't do this!
    if (thatValue == TRUE)   // Or this!
    if (otherValue != TRUE)  // Whatever you do, don't do this!
    

    为什么?因为许多程序员使用将 int s视为 bool 的快捷方式 . 他们写作是完全合法的

    if (strcmp(yourString, myString) == TRUE)  // Wrong!!!
    

    这看起来很合理,编译器会很乐意接受它,但它可能并不需要 . 那是因为 strcmp() 的返回值是

    0如果 yourString == myString
    <0 if yourString < myString

    0如果 yourString > myString

    所以上面的行仅在 yourString > myString 时返回 TRUE .

    正确的方法是这样做

    // Valid, but still treats int as bool.
    if (strcmp(yourString, myString))
    

    要么

    // Better: lingustically clear, compiler will optimize.
    if (strcmp(yourString, myString) != 0)
    

    同理:

    if (someBoolValue == FALSE)     // Redundant.
    if (!someBoolValue)             // Better.
    return (x > 0) ? TRUE : FALSE;  // You're fired.
    return (x > 0);                 // Simpler, clearer, correct.
    if (ptr == NULL)                // Perfect: compares pointers.
    if (!ptr)                       // Sleazy, but short and valid.
    if (ptr == FALSE)               // Whatisthisidonteven.
    

    你会经常在 生产环境 代码中找到一些这些“不好的例子”,许多有经验的程序员都会发誓:他们工作,有些比他们(迂腐?)正确的选择更短,而成语几乎被普遍认可 . 但要考虑:“正确”的版本效率并不低,它们保证可移植,即使是最严格的连接也会通过,甚至新程序员也会理解它们 .

    这不值得吗?

  • 2

    (1 == 1) 技巧对于以对C透明的方式定义 TRUE 非常有用,但在C中提供了更好的输入 . 如果您使用名为"Clean C"(可编译为C或C)的方言编写,或者您正在编写可由C或C程序员使用的API头文件,则可以将相同的代码解释为C或C.

    在C翻译单元中, 1 == 11 具有完全相同的含义;和 1 == 0 的含义与 0 相同 . 但是,在C转换单元中, 1 == 1 的类型为 bool . 所以 TRUE 宏定义的方式更好地集成到C中 .

    它如何更好地集成的示例是,例如,如果函数 foo 具有 intbool 的重载,则 foo(TRUE) 将选择 bool 重载 . 如果 TRUE 刚刚被定义为 1 ,那么它在C中将无法正常工作 . foo(TRUE) 会想要 int 重载 .

    当然,C99引入了 booltruefalse ,这些可以在与C99和C一起使用的头文件中使用 .

    然而:

    • 这种将 TRUEFALSE 定义为 (0==0)(1==0) 的做法早于C99 .

    • 仍然有充分理由远离C99并与C90合作 .

    如果您想要C99,请定义小写 truefalsebool .

    #ifndef __cplusplus
    typedef int bool;
    #define true (0==0)
    #define false (!true)
    #endif
    

    话虽如此, 0==0 技巧是(是?)使用一些程序员甚至在代码中从未打算以任何方式与C互操作 . That doesn't buy anything and suggests that the programmer has a misunderstanding of how booleans work in C.


    如果C解释不清楚,这是一个测试程序:

    #include <cstdio>
    
    void foo(bool x)
    {
       std::puts("bool");  
    }
    
    void foo(int x)
    {
       std::puts("int");  
    }
    
    int main()
    {
       foo(1 == 1);
       foo(1);
       return 0;
    }
    

    输出:

    bool
    int
    

    关于如何重载C函数与混合C和C编程相关的评论中的问题 . 这些仅仅说明了类型差异 . 编译为C时,希望 true 常量为 bool 的正当理由是进行清洁诊断 . 在最高警告级别,如果我们将整数作为 bool 参数传递,C编译器可能会警告我们转换 . 在Clean C中编写代码的一个原因不仅是我们的代码更易于移植(因为C编译器理解它,而不仅仅是C编译器),但我们可以从C编译器的诊断意见中受益 .

  • 12
    #define TRUE (1==1)
    #define FALSE (!TRUE)
    

    相当于

    #define TRUE  1
    #define FALSE 0
    

    在C.

    关系运算符的结果是 01 . 保证 1==1 被评估为 1 ,并且保证 !(1==1) 被评估为 0 .

    绝对没有理由使用第一种形式 . 请注意,第一种形式的效率并不低于几乎所有编译器,在编译时而不是在运行时评估常量表达式 . 根据此规则允许这样做:

    (C99,6.6p2)“可以在翻译期间而不是运行时评估常量表达式,因此可以在常量可能的任何位置使用 . ”

    如果你不使用 TRUEFALSE 宏的文字,PC-Lint甚至会发出一条消息(506,常量值布尔值):

    对于C,TRUE应定义为1.但是,其他语言使用的数量不是1,因此一些程序员认为!0正在安全地播放 .

    同样在C99中,布尔宏 truefalsestdbool.h 定义直接使用文字:

    #define true   1
    #define false  0
    
  • 3

    除了C(已经提到)之外,另一个好处是静态分析工具 . 编译器将消除任何低效率,但静态分析器可以使用自己的抽象类型来区分比较结果和其他整数类型,因此它隐式地知道TRUE必须是比较的结果,不应该被认为是兼容的用整数 .

    显然C表示它们是兼容的,但是您可以选择禁止故意使用该功能来帮助突出显示错误 - 例如,有人可能会混淆 &&& ,或者他们已经搞砸了运营商的优先权 .

  • 136

    实际的区别是没有 . 0 评估为 false1 评估为 true . 您使用布尔表达式( 1 == 1 )或 1 来定义 true 的事实没有任何区别 . 它们都被评估为 int .

    请注意,C标准库提供了用于定义布尔值的特定标头: stdbool.h .

  • 154

    我们不知道TRUE等于的确切值,编译器可以有自己的定义 . 因此,您所要求的是使用编译器的内部定义 . 如果您有良好的编程习惯,但并不总是必须这样做,但可以避免一些不良编码风格的问题,例如:

    if((a> b)== TRUE)

    如果您将TRUE定义为1,而内部值TRUE为另一个,则可能会造成灾难 .

  • 3
    • 列出项目

    通常在C编程语言中,1定义为true,0定义为false . 因此,为什么你经常看到以下内容:

    #define TRUE 1 
    #define FALSE 0
    

    但是,在条件语句中,任何不等于0的数字都将被计算为true . 因此使用以下内容:

    #define TRUE (1==1)
    #define FALSE (!TRUE)
    

    你可以明确地表明你试图通过使虚假等于任何不真实的东西来安全地发挥它 .

相关问题