#define TRUE !FALSE vs #define TRUE 1

7

先不考虑自c99起已经存在 stdbool.h ,在定义处理C中的布尔类型的宏时,以下两种方法有什么区别吗?

#define FALSE 0

#define TRUE 1       // Option 1 
#define TRUE !FALSE  // Option 2

这个实例来看,好像没有区别。有没有技术上的优势?(不包括第二个示例可以更好地处理c++中的bool对象的事实。)

4
能否解释一下为什么被踩一下会更好。 - Fantastic Mr Fox
为什么不使用 stdbool.h?在标准宏存在的情况下使用自制宏是一个非常糟糕的想法。 - too honest for this site
@Olaf 主要想澄清在这里发生的讨论:http://stackoverflow.com/questions/35565191/condition-is-always-true-when-i-know-its-not?noredirect=1#comment58819429_35565191 - Fantastic Mr Fox
@Olaf:只有在包含了<stdbool.h>头文件时,truefalsebool才会被定义。 - Keith Thompson
@Olaf:C99中的_Bool/bool特性被精心设计,以避免破坏使用标识符truefalsebool的现有代码。我想未来的C标准可能会使它们都成为关键字(类似于C++),但我会感到惊讶。(非原型函数声明自1989年以来已经过时,28年后我们仍然卡在这里。) - Keith Thompson
显示剩余10条评论
7个回答

13

ISO C和C99都这样定义!

逻辑非运算符!的结果是0,如果其操作数的值与0不相等,则为1。结果的类型为int。表达式!E等效于(0==E)。

因此,!0的计算结果为1假设使用符合标准的C编译器,两个选项将具有相同的结果。此外,没有运行时惩罚,编译器将在编译时将!0折叠为1


如果您想将其推向逻辑的极端,并且不做任何有关真或假的假设......

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

这样做的好处是不管使用哪种语言都始终如一。例如,在 shell 中,0 通常被认为是“true”或“not an error”。这种做法是一个过时的东西,源于 C 语言没有一个统一的标准的时代。比如,Code Complete 的第一版在第369页上提倡这种方法。1993年出版时,你的C编译器很可能不符合ISO标准,而且stdbool.h也不存在。"Code Complete"也适用于掌握多种不同语言的程序员。一些语言(如shell和Lisp)定义真值的方式也不相同。

即使在1993年,如果(1 == 1)不产生值为1int类型或者!(1 == 1)不产生值为0int类型,我仍然会感到惊讶。我相信,将TRUE定义为1,将FALSE定义为0一直是有效的,只要存在一种名为“C”的语言(可能追溯到B和BCPL)。 - Keith Thompson
@KeithThompson在Code Compete中的上下文中更有意义,因为它是一本真正的多语言编程书籍。它并不是特定于C的东西,而是一种多语言编程实践。作者认为这在任何语言中都可以工作。 - Schwern

3

选项2没有任何好处,因为C标准保证! 0的结果是1。

以那种方式定义TRUE是旧源代码的主要特点,可能是为了遵循样式指南,尽可能避免使用"神奇常数"。


但是 ! 不是在使用 TRUE 时必须始终执行的附加操作吗?(假设编译器没有针对其进行优化)?如果不是,那么 !0 = 1 部分是在哪里处理的呢? - Markus Weninger
3
常量折叠是C编译器自问世以来一项微不足道的优化技术,现代编译器即使关闭了优化选项也会实现这一功能。换句话说,你可以放心地指望编译器将其优化掉。 - user4815162342
"即使关闭优化,现代编译器也可以做到这一点。正如我所想的那样,谢谢你帮我明白了。" - Markus Weninger
1
Visual Basic 将 TRUE 表示为 -1(所有位都设置),所以如果旧的 C 编译器做了类似的事情,我也不会感到惊讶。 - user253751
1
@immibis:如果旧的 C 编译器做了类似的事情,我会感到惊讶。1974 年(比 K&R1 早四年)的 C 手册说,内置布尔运算符(!==< 等)对于 false 产生 0,对于 true 产生 1 - Keith Thompson

3
#define FALSE 0

#define TRUE 1       // Option 1 
#define TRUE !FALSE  // Option 2

这些值没有区别。 1!0 都是类型为 int 的常量表达式,具有相同的值 1(根据标准对 ! 运算符语义的定义)。

可能存在一个区别,即第二个定义没有正确地加括号。请记住,在表达式中展开未加括号的宏会导致运算符优先级问题。我在这里写了一个人为制造的例子。

由于一元运算符 ! 具有非常高的优先级,您不太可能遇到问题。 我能想到的唯一情况是,如果将其用作索引运算符的前缀。 例如,给定:

int arr[] = { 10, 20 };

选项1会产生以下结果:

TRUE[arr] == 20

选项2提供的是:
TRUE[arr] == 0

为什么要这样做呢?请记住,数组索引是可交换的(参见此问题我的回答),而索引运算符[]!具有更高的优先级。
这里的教训是:
  1. 对于任何旨在用作表达式的宏,整个宏定义都应该用括号括起来 - 即使你想不到会产生影响的情况。

  2. 保持简单。在C中,0是唯一的假值,1是规范的真值。(任何非零值都为“真”,但内置的“布尔”运算符总是产生01。)使用!运算符将TRUE定义为FALSE(反之亦然)只是一种不必要的复杂化。

如果可以,请使用<stdbool.h>。如果不能(因为你被困在一个C99之前的编译器中),我建议这样做:
typedef enum { false, true } bool;

这与C99的_Bool / bool不完全相同(转换为此 bool 类型不会标准化为 0 1 ),但对于几乎所有目的而言都足够接近。


我认为你是指!0(第一句话)。另外,我同意关于宏括号的问题,不确定为什么我没有在这里包含它们。 - Fantastic Mr Fox
@Ben:是的,我指的是!0;我已经修复了它。 - Keith Thompson

2

差别不大。

#define TRUE 1 相对于 #define TRUE !FALSE 稍微占有一点优势,因为 1 是一个单独的项目,不受运算符优先级的影响。

!FALSE 可以被写成 (!FALSE),以适应那些尝试使用 ++ -- [] . -> 的奇怪代码,这些运算符与 FALSE 有更高的优先级。


1
哦!那是个好观点,我无法想象++TRUE的用途,但我可以想象它会引发麻烦。 - Fantastic Mr Fox
@Ben:++TRUE会出错,因为你不能对一个常量值应用++运算符——但是我在我的答案中有另一个例子。 - Keith Thompson

0

没有太大区别。但我认为#define TRUE 1更好。

如果您使用#define TRUE !FALSE

FALSE是0,而TRUE是除了0以外的所有数字。

如果您使用#define TRUE 1

FALSE是0,而TRUE是1。没有问题。


0

在 C 语言中,TRUE 被正确定义为 (!FALSE),因为零 (0) 是 FALSE,而 FALSE 是零 (0),任何其他值都是 TRUE。你几乎可以使用任何变量作为布尔表达式,如果它非零,则表达式的值为 TRUE。一个空指针就是零,这正是它被定义为 NULL 的原因。字符串的结束标志字符 ('\0') 也是零。有很多代码利用了这个事实。请考虑以下示例:

while ( *d++ = *s++ ); 

复制将在复制完结束字符串字符时结束。这个习惯用语非常普遍。不必担心缓冲区大小问题。

这是为什么如果您没有现代的专用布尔类型,其中唯一可能的值为TRUE和FALSE,那么测试等于TRUE是一个坏主意的一个原因。我建议您养成无论如何都测试不等于FALSE的习惯,出于安全考虑。您可能并不总是能够使用新的、闪亮的工具。


-2

它们只是相同的。

  • !01,所以 !FALSE1

#define TRUE !FALSE 没有任何技术上的好处,尽管它存在了很长时间并出现在许多地方。

#define TRUE !FALSE 可能会被误解,人们可能会认为 TRUE 代表不等于 0 的每个值。

  • 只有 1 等于 TRUE,其他值如 23255...(!=0)不等于 TRUE

为了防止这种误解,许多组织要求不再使用 #define TRUE !FALSE 或将与 TRUE 的比较更改为 !FALSE

// Should not     
if (var_bool == TRUE) {
...
}

//Should    
if (var_bool != FALSE) {
...
}

好的,你的编辑让事情变得清晰了。你拿了一个关于条件语句的样式指南,并错误地将其扩展到所有使用 ! 的情况。而且你搞反了,因为它看起来确实像是在倡导双重否定。你应该使用 var_bool == TRUEvar_bool == TRUEvar_bool != FALSE 更清晰。或者我应该说 var_bool == TRUE 不比 var_bool != FALSE 更不清晰?;) 而且 if( var_bool ) 更加不不清晰。 - Schwern
1
@user4815162342 这就是为什么写 if( var_bool )if( !var_bool ) 更好。 - Schwern
2
@IlDivinCodino 它说的是一直在说的事情。同样的反对意见适用。var_bool != FALSE 是一个双重否定,增加了复杂性,应该避免使用(或者我应该说“不会增加简单性,不应该使用”)。一个体面的风格将推荐 if( var_bool ) 来完全避免这个问题。任何能够编写工作的 C 代码的人都不会认为 #define TRUE !FALSE 可能会将 TRUE 设置为 255 或 2 或 3,而且这些都不重要,因为它不应该被用作数字。 - Schwern
3
@IlDivinCodino 我们对此有共识。"TRUE和FALSE的目的"是为了帮助可读性,即使得清晰明确some_function(FALSE)意图将逻辑上的假值发送给some_function,而不是整数0。比较真值测试不起作用,因为在C语言中,所有非零数字值和非NULL指针都是逻辑上的真值。比较FALSE失败,因为仅将FALSE改为TRUE即可破坏测试。那些规定这样做的风格指南是误导人的 - 在C语言中,应始终使用if (...)if (!...)来测试真值。 - user4815162342
1
你能提供一个实际的C语言风格指南的参考,它规定了在使用if (x != FALSE)if (x == FALSE)时优先于使用if (x)if (!x)吗?我从未见过这样的指南。 - user4815162342
显示剩余13条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接