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

我已经看过C中的定义

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

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

如果编译器支持,这种方法将使用实际的booleantypes(并parsing为truefalse )。 (特别是C ++)

但是,最好检查一下C ++是否正在使用(通过__cplusplusmacros),实际使用truefalse

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

答案是可移植性。 TRUEFALSE的数值并不重要。 重要的是像if (1 < 2)这样的语句的计算结果为if (TRUE)if (1 > 2)计算结果为if (FALSE)

当然,在C中, (1 < 2)评价为1(1 > 2)评价为0 ,所以如其他人所说,就编译器而言,没有实际的区别。 但是通过让编译器根据自己的规则定义TRUEFALSE ,就可以使程序员明确地expression它们的含义,并且保证程序和其他库的一致性(假设其他库遵循C标准)会惊讶的)。


一些历史
一些BASIC将FALSE定义为0TRUE定义为-1 。 像许多现代语言一样,他们任何非零值解释TRUE ,但他们评估的布尔expression式为-1 。 他们的NOT操作是通过加1和翻转符号来实现的,因为这样做效率很高。 所以'不x'变成-(x+1) 。 这样做的一个副作用是像5的值评估为TRUE ,但NOT 5评估为-6 ,这也是TRUE ! 发现这种错误并不好玩。

最佳实践
给定零被解释为FALSE 事实规则,并且任何非零值被解释为TRUE ,您不应将布尔型expression式与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()的返回值是

0如果yourString == myString
<0如果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. 

在生产代码中,你经常会发现一些这样的“坏例子”,许多有经验的程序员发誓:他们工作,有些比他们的(迂回的)正确的select更短,成语几乎得到普遍认可。 但是考虑一下:“正确”的版本效率不低,保证是可移植的,甚至会通过最严格的短语,甚至新的程序员也会理解它们。

这不值得吗?

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

在C翻译单元中, 1 == 1的含义与1完全相同, 和1 == 0的含义与0相同。 但是,在C ++翻译单元中, 1 == 1types为bool 。 所以TRUEmacros定义的方式更好地整合到C ++中。

例如,如果函数foo具有intbool重载,那么foo(TRUE)将selectbool重载。 如果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 ++的解释不清楚,这里是一个testing程序:

 #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 ++函数的重载问题。 这些只是说明types的差异。 当编译为C ++时,想要一个true常量是一个有效的理由是纯粹的诊断。 在最高的警告级别,如果我们将整数作为boolparameter passing,C ++编译器可能会警告我们有关转换。 在Clean C中编写的一个原因不仅在于我们的代码更具可移植性(因为它被C ++编译器理解,而不仅仅是C编译器),但是我们可以从C ++编译器的诊断意见中受益。

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

相当于

 #define TRUE 1 #define FALSE 0 

在C.

关系运算符的结果是011==1保证评估为1!(1==1)保证评估为0

绝对没有理由使用第一种forms。 请注意,第一种forms的效率并不像几乎所有的编译器那样有效,因为常量expression式是在编译时而不是在运行时计算的。 根据这个规则,这是允许的:

(C99,6.6p2)“一个常量expression式可以在翻译过程中而不是在运行时进行评估,因此可以用在常量可能的任何地方。

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

对于C, TRUE应该定义为1 。 然而,其他语言使用的数量不是1,所以一些程序员认为!0是安全的。

同样在C99中,booleanmacros的stdbool.h定义truefalse直接使用文字:

 #define true 1 #define false 0 

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

很明显C说它们是兼容的,但是你可以select禁止有意使用这个特性来帮助突出错误 – 例如,有人可能会把&&&混淆起来,或者他们已经妨碍了它们的运算符优先级。

实际的区别是没有。 0评估为false1评估为true 。 您使用布尔expression式1 == 1 )或1来定义true并没有什么区别。 他们都被评估为int

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

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

如果((a> b)== TRUE)

如果你把TRUE定义为1,这可能是一个灾难,而TRUE的内部值是另一个。

  1. 项目清单

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

 #define TRUE 1 #define FALSE 0 

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

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

你可以明确地表明你试图通过使虚假等于任何不正确的方式来保证安全。