在C语言中使用true和false

95
据我所见,在C语言中使用布尔值有三种方法:
1. 使用bool类型,从导入,然后使用true和false。 2. 使用预处理器定义,例如#define FALSE 0 ... #define TRUE !(FALSE)。 3. 直接使用常量,即1和0。
还有其他我可能忽略的方法吗?不同方法之间的优缺点是什么?
我认为最快的方法应该是第三种,第二种更易读(尽管位取反会稍微增加开销),而第一种最易读但不兼容所有编译器。

42
你真的认为编译器会在运行时才否定一个常量吗? - GManNickG
25
为了跟进以免看起来像个傻瓜,没有编译器会浪费时间去做那件事。编译器都是强大的优化器,如果它知道结果总是相同的,它就会把结果放在代码里面。它不会等到运行时再去计算 int i = 12 + 3 * 4;;它会直接写成 int i = 24;。担心性能问题是一个常见的问题,不要感到难过。优化是最后才考虑的事情,当你需要进行优化时,你必须计时并查看汇编输出,而不是猜测。即使它耗费了一个周期,我也会选择最易读的解决方案。只有在证明它是一个瓶颈时,我才会寻求更好的性能。 - GManNickG
12
如果我要切换到更快的解决方案,我会测试它们的时间,以确保它们确实更快。当需要在可读性和执行速度之间做出选择时,请选择可读性。 :) 编写高效的代码很容易,但将“快速”的代码变得良好却很困难。 - GManNickG
20
使用宏时,请记住(x == TRUE)(x)不是相同的。前者只有当x的值为TRUE时才为真,而后者对于任何非零值都为真。 - Devon_C_Miller
6
我建议不要定义特殊的布尔宏,因为这会促使新手程序员编写像 if(foo == TRUE)if(foo == FALSE) 这样的代码,这在大多数语言中都是可怕的,但在 C 语言中更加如此,因为在布尔环境下任何标量值 != 0 都被认为是 true;出于类似但较轻微的原因,我不喜欢用 if(foo != NULL)if(foo == NULL) 来判定指针是否为空;虽然这不会像与 TRUE 的比较一样引入错误,但仅仅是口味问题而已。然而,对于任何标量值,使用 if(foo)if(!foo) 更符合 C 语言的外观和感觉。 - Christoph
显示剩余5条评论
15个回答

145

如果您的系统支持,只需包含<stdbool.h>即可。 这将定义许多宏,包括boolfalsetrue(分别定义为_Bool、0和1)。 有关更多详细信息,请参见C99第7.16节。


13
“bool”不是一个宏,其类型为“_Bool”。否则会严重破坏旧代码。 - Lothar
7
可以在不包含"stdbool.h"头文件的情况下使用"_Bool"。 - Christoph

22

在代码中直接使用0或1即可。

对于C程序员来说,这与true或false一样直观。


63
对于C程序员来说,-1也被视为真,因为它不是零。事实上,42和-234也是真值。我曾经看到过-1、-2和其他值作为真。有些函数返回0(零)表示成功。哎呀,一致性就这样被打破了。 - Thomas Matthews
8
我同意Thomas的观点。事实上,将0用作“无错误”的错误代码(并且通常也用作int类型)有时会使一个值是否应在布尔上下文中使用变得不明显。 - jamesdlin
13
将一个返回0表示无错误的函数视为回答问题“是否遇到了任何问题?”的方式,“0=false=no”。 如果 int fail = close(fd); 返回值为0,则执行 great();,否则执行weep(); - squelart
2
@squelart:问题在于很多返回布尔值的函数并没有这种语义,它们在成功时返回true值,在失败时返回false值。(例如,许多Win32 API都是这样设计的。) - jamesdlin
1
返回0表示成功的模式是更大模式的一部分,如下所示:如果函数成功,则返回正整数值(例如,处理的字节数、经过的时间等)。通过返回负整数来指示失败。如果我们现在将此模式应用于仅返回成功或失败的函数,则失败将表示为-1,成功将表示为0。许多Linux / Unix系统调用和库函数遵循此模式,因此熟悉它是很好的。 - John Vincent
显示剩余4条评论

21

我通常执行以下操作:

typedef enum {FALSE = 0, TRUE} boolean;

6
你为什么要明确设置FALSE=0?枚举的第一个元素不是自动为0吗? - lindelof
17
只是为了防止他们在该枚举前加上“FileNotFound”。;-) - C. K. Young
2
@lindelof 这很有道理。确保 FALSE 是 0,这是唯一重要的事情。只要 TRUE 不同,它可以是任何东西。 - klutt

6
无论你选择哪一个,都要将变量与FALSE或false进行比较。
在C或C++中,将任何东西与true(1)进行比较历史上都是一个不好的想法。只有false被保证为零(0)。True是任何其他值。
许多编译器供应商在其头文件中都有这些定义。
#define TRUE 1
#define FALSE 0

这导致很多人走进了歧途。
许多库函数除了chartype之外,在成功时返回非等于1的非零值。许多遗留代码也有相同的行为。

3
我注意到,与TRUE进行比较会导致未初始化变量的失败。最好初始化布尔值并与FALSE进行比较。如果确实需要三个值 - 否,是和不知道,则枚举类型更好。将枚举类型初始化为不知道。不要将枚举类型看作布尔类型。它不是。 - Bob Wakefield
为什么不使用 #define TRUE !FALSE #define FALSE 0 - The incredible Jan
那样就可以了。但这并不能解决针对TRUE进行测试的根本问题。 - Bob Wakefield

5

使用stdbool.h定义的bool类型,在需要将代码从支持bool类型的新编译器移植到旧编译器时会出现问题。在嵌入式编程环境中,当您使用基于较旧规范版本的C编译器移植到新架构时,可能会发生这种情况。

总之,如果需要可移植性,建议使用宏。否则,可以按照其他人的建议使用内置类型。


4
除了零以外的任何整数都是true;false就是零。这样,像这样的代码仍然按预期工作:
int done = 0;   // `int` could be `bool` just as well

while (!done)
{
     // ...
     done = OS_SUCCESS_CODE == some_system_call ();
}

在我看来,bool 是一种被高估的类型,可能是从其他语言中遗留下来的。 int 同样可以作为布尔类型。


1
关于“被高估”的问题:在C++中,bool是一种独立的类型,因此它可以参与函数重载,这与字符常量在C++中是char类型的原因很相似。当然,在没有函数重载的C语言中,这并不适用。 - C. K. Young
7
不行,C语言存在缺陷,无法区分布尔值和整数。 - starblue
2
C语言几乎不会出错。整数是一组布尔值,可以并行操作。将整个集合作为一个整体进行评估,其结果为它们的逻辑或值。 - wallyk
1
@starblue:C99引入了一个专门的布尔类型;如果这让你放心,你可以假装C会自动将标量值转换为布尔上下文中的_Bool,这是许多动态语言中也存在的特性。 - Christoph
2
_Bool的好处在于它允许编译器以最佳方式存储它(一个字节、一个字、一个位,或者其他任何方式);甚至可以让您在编译时确定其大小(就像某些编译器中,您可以将int指定为2或4个字节,或将long指定为4或8个字节)。有一个想要将事物作为字访问的处理器?将_Bool设置为字大小。你的处理器能像访问字一样轻松地访问字节吗?将它设置为字节以节省空间。有位访问指令吗?也许是,也许不是。继续C语言长久以来不固定int大小的传统... - Mike DeSimone
显示剩余2条评论

4
你可以使用C99的stdbool.h来测试bool是否被定义。
#ifndef __bool_true_false_are_defined || __bool_true_false_are_defined == 0
//typedef or define here
#endif

抱歉关于我上一条评论,我的PDF搜索功能出了问题。请参阅第7.16节以获取有关__bool_true_false_are_defined的更多信息。 - C. K. Young

2

我曾经使用#define,因为它们使代码更易于阅读,并且与使用数字(0,1)相比不应该存在性能下降,因为预处理器在编译之前将#define转换为数字。一旦应用程序运行,预处理器就不再起作用了,因为代码已经编译。

顺便说一句,应该是:

#define FALSE 0 
#define TRUE 1

请记住,-1、-2、... 2、3 等都会被视为 true。


TRUE 是一个只写的值 - 在读取/比较等操作中,任何非零值都需要被视为真。 - Jerry Coffin
2
由于某些原因,TRUE 似乎通常被定义为 #define TRUE !(FALSE)。 - Tom
3
@Tom - 这是因为 !1 返回 0,但是 !0 返回一个真值,可能是各种不同的数字。#define TRUE !(FALSE) 确保无论 !0 返回什么确切的值,都能使得 TRUE == !0 - Chris Lutz

2

我不知道你的具体情况。在我写C程序时,我们总是使用#2。


(注:该段内容为对某个问题的回答,提到了在编写C程序时常用的方法)
#define FALSE = 0
#define TRUE = !FALSE

这可能与DOS或基于英特尔处理器的平台不同。但我曾经使用C和ASM编写图形库和图形化IDE。我是Micheal Abrash的真正粉丝,打算学习纹理映射等相关知识。无论如何!那不是这里问题的主题!

这是在C语言中定义布尔值最常用的方式,因为当时并不存在这个头文件stdbool.h。


1
你可能想要这样做:#define TRUE = (!(FALSE)) - ant2009
1
#define TRUE = 1有什么优势? - endolith
7
首先,在 #define 中不要使用等号(=)。其次,只有 FALSE 有一个已定义的值;即零。TRUE 是任何其他的值。 - Bob Wakefield

2

我会选择1。我没有遇到过它的不兼容性,并且更加自然。但是,我认为它是C++的一部分,而不是C标准。我认为通过定义的肮脏黑客或您的第三个选项 - 不会获得任何性能,只会给代码维护带来痛苦。


5
bool 是 C++ 的一部分,但 _Bool (使用 bool 作为别名) 现在是 C 的一部分(从 C99 开始)。 - Jerry Coffin
我不会选择1,因为任何非零值都是true。所以对于有符号的量,-1也是true。 - Thomas Matthews
我的意思是选项1...使用布尔类型。 - anthares

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