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

时间:2013-06-09 13:22:23

标签: c precompiler

我见过C中的定义

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

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

8 个答案:

答案 0 :(得分:153)

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

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

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

答案 1 :(得分:136)

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

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


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

最佳做法
鉴于事实上的规则将零解释为FALSE任何非零值被解释为TRUE,您应该从不将看似布尔的表达式与TRUEFALSE 进行比较。例子:

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()的返回值是

如果yourString == myString,则

0 &lt; 0 if yourString < myString
&gt; 0如果yourString > myString

因此,上述行仅在TRUE时返回yourString > myString

正确的方法是

// 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 :(得分:50)

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

在C翻译单元中,1 == 11的含义完全相同; 1 == 00具有相同的含义。但是,在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合作。

如果您正在使用混合C和C ++项目,并且不想要C99,请改为定义小写truefalsebool

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

话虽如此,0==0技巧是(是?),即使在从未打算以任何方式与C ++进行互操作的代码中也会使用。 那不买任何东西,并暗示程序员误解了布尔在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 ++编译器的诊断意见中受益。

答案 3 :(得分:18)

#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中,布尔宏stdbool.htrue的{​​{1}}定义直接使用文字:

false

答案 4 :(得分:12)

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

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

答案 5 :(得分:3)

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

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

答案 6 :(得分:3)

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

if((a> b)== TRUE)

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

答案 7 :(得分:2)

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

    #define TRUE 1 
    #define FALSE 0
    

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

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

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