在C中使用对与错


75

据我所知,有3种在c语言中使用布尔值的方法

  1. 从布尔类型开始,然后使用true和false
  2. 使用预处理器进行定义 #define FALSE 0 ... #define TRUE !(FALSE)
  3. 只是直接使用常量,即1和0

还有其他我错过的方法吗?不同方法的优缺点是什么?

我想最快的将是数字3,2仍然更容易阅读(尽管按位取反会稍微增加开销),1可读性最高而不与所有编译器兼容。


38
您实际上认为编译器要等到运行时取反常量吗?
GManNickG

24
要跟进,这样我就不会觉得混蛋,没有编译器会浪费时间。编译器是最繁琐的优化器,如果知道结果将始终相同,则将其放在那儿。它永远不会等到运行时进行评估int i = 12 + 3 * 4;; 它只会说int i = 24;。担心这样的性能是一个常见问题,不要感到难过。优化是最后一个,当它实现时,您必须计时代码并查看程序集输出,而不是猜测。即使花费了一个周期,我还是会选择最易读的解决方案。仅当它被证明是
GManNickG 2010年

11
问题是我会切换到更快的解决方案,并对它们进行计时以确保它们确实更快。如果在可读性和循环之间做出选择,请选择可读性。:)轻松编写良好的代码很容易,但是很难制作出“快速”代码。
GManNickG

20
使用宏时,请记住与宏(x == TRUE)不同(x)。前者只有在x具有的值时才是正确的TRUE。后者适用于任何非零值。
Devon_C_Miller

6
我建议不要定义特殊的布尔宏。这仅会诱使新手程序员编写诸如if(foo == TRUE)或的代码if(foo == FALSE),这在大多数语言中都是很糟糕的,而在C语言中则更是如此,在C语言中,任何标量值!= 0在布尔上下文中都被认为是正确的;类似的,但不太严重的原因,我不喜欢if(foo != NULL)if(foo == NULL)为指针; 因为这不能将bug作为可以比较的TRUE方法,所以仅是口味问题,但是使用if(foo)if(!foo)标量值更适合C语言的外观和风格
Christoph

Answers:


117

<stdbool.h>在系统提供的情况下包括。定义了许多宏,包括boolfalsetrue(分别定义为_Bool,0和1)。有关更多详细信息,请参见C99的7.16节。


11
没有“布尔”是宏。类型是“ _Bool”。否则,它将严重破坏旧代码。
Lothar 2010年

6
您可以_Bool不使用就使用stdbool.h
Christoph

21

只需在代码中直接使用0或1。

对于C程序员来说,这是对还是错。


45
对于C程序员,-1也是如此,因为它不是零。因此,42和-234也是真实值。我已经看到-1,-2和其他值是正确的。某些函数成功返回0(零)。嗯,一致性很重要。
Thomas Matthews'2

1
我通常只看到1或-1用作真实值。-1,因为它全为二进制。我想知道你在哪里找到-2。
Mike DeSimone 2010年

7
我同意托马斯的观点。使用0作为“无错误”的错误代码(通常也作为int类型)的事实有时使人们不清楚是否应该在布尔上下文中使用值。
jamesdlin

9
考虑一个无错误返回0的函数,以回答“您有任何问题吗?”的问题。-“ 0 =假=否”。int fail = close(fd); if (!fail) { great(); } else { weep(); }
squelart

1
@squelart:问题在于很多返回布尔值的函数没有这种语义,并且在成功时返回真值,在失败时返回假值。(例如,许多Win32 API都是以这种方式设计的。)
jamesdlin

17

我通常会做:


5
为什么要显式设置FALSE = 0?枚举的第一个元素不是自动为0吗?
lindelof

10
@lindelof以防万一它们添加FileNotFound到该枚举的前面。;-)
Chris Jester-Young

1
@lindelof这是有道理的。确保FALSE为0是唯一重要的事情。TRUE可以是任何东西,只要它不同即可。
klutt

5

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

总之,当可移植性很重要时,我会坚持使用宏。否则,请执行其他人的建议并使用bulit。


5

无论您使用哪三个,请将变量与FALSE进行比较,否则为false。

从历史上看,在c或c ++中将任何内容与true(1)进行比较都是一个坏主意。只有false保证为零(0)。真是其他任何价值。许多编译器供应商的标头中都有这些定义。  

这导致太多人沿着花园小路走。许多库函数除了chartype返回不等于1成功值的非零值之外,还返回其他值。有很多具有相同行为的遗留代码。


2
我注意到,对TRUE的比较对未初始化的变量失败。最好初始化您的布尔值并与FALSE进行比较。如果您确实需要三个值,那么枚举会更好。不,是,不知道。初始化枚举不知道。不要将枚举视为布尔值。不是。
Bob Wakefield

3

您可以使用以下命令测试是否在c99 stdbool.h中定义了bool:


对不起,我的最新评论,我的PDF搜索工具已损坏。有关更多信息,请参见第7.16节__bool_true_false_are_defined
克里斯·杰斯特·杨

2

我会争取1。我没有遇到不兼容的情况,这很自然。但是,我认为它是C ++而不是C标准的一部分。我认为使用define或第三个选项进行肮脏的黑客攻击-不会获得任何性能,而只会维护代码。


5
bool是C ++的一部分,但是_Bool(带有bool别名)现在是C的一部分(从C99开始)。
杰里·科芬

很高兴知道。谢谢。:)
anthares 2010年

我不会选择1,因为任何非零值都为true。因此,对于带符号的数量,-1也是如此。
Thomas Matthews 2010年

我的意思是选项1 ...具有布尔类型
anthares 2010年

2

我更喜欢(1)当我定义一个变量,但在表达式中我从不与true和false进行比较时,只接受if(flag)或if(!flag)或if(ptr)的隐式C定义。那就是C做事的方式。


2

除零以外的任何int都是真实的;假为零。这样的代码将继续按预期工作:

IMObool是一种被高估的类型,可能是其他语言的遗留物。 int可以作为布尔类型正常工作。


1
关于“过高”的说明:在C ++中,它bool是一个单独的类型,因此它可以参与函数重载,原因与char在C ++中字符常量是类型的许多原因相同。当然,这不适用于没有函数重载的C语言。
克里斯·杰斯特·杨

5
不,C被破坏了,因为它无法区分布尔值和整数。
starblue 2010年

1
C几乎不会损坏。整数是一组布尔值,可以并行操作。整体评估集合是它们的ORed值。
wallyk'2

1
@starblue:C99引入了专用的布尔类型;如果您不介意的话,您可以假装C会自动将标量值转换为_Bool布尔值上下文,这也是许多动态语言中都具有的功能
Christoph 2010年

2
令人高兴的_Bool是,它允许编译器以最有效的方式(字节,字,位或其他方式)存储它;甚至可以给您选择在编译时确定其大小的选项(例如在某些编译器中,您可以将其指定int为2或4个字节,或者指定long为4或8个字节)。是否有一个处理器想以单词的形式访问事物?使_Bool单词大小。您的处理器是否像字一样容易访问字节?使其成为一个字节以节省空间。有位访问说明?也许吧,也许不是。延续C悠久的传统,即不缩小int尺寸……
Mike DeSimone 2010年

1

我以前使用#define是因为它们使代码更易于阅读,并且与使用数字(0,1)相比,性能不应降低,因为预处理器在编译之前将#define转换为数字。一旦应用程序运行,预处理器就不会再次出现,因为代码已经被编译。

顺便说一句,它应该是:

并记住-1,-2,...,2、3等都计算为true。


TRUE是只写值-读/比较等时,任何非零值都应视为true。
杰里·科芬

2
由于某些原因,TRUE通常被定义为#define TRUE!(FALSE)
汤姆

3
@Tom-这是因为!1返回0,但!0返回一个真值,该值可能是各种各样的数字。#define TRUE !(FALSE)确保TRUE == !0无论!0返回什么确切值。
克里斯·卢茨

1

我不知道你的具体情况。回到我编写C程序时,我们一直使用#2。

否则,这可能是在DOS或基于Intel的处理器的外来平台下。但是我曾经同时使用C和ASM来编写图形库和图形IDE。我是Micheal Abrash的忠实粉丝,并打算学习纹理映射等等。无论如何!这不是这里的问题!

这是在C中定义布尔值的最常用形式,因为那时该头文件stdbool.h不存在。


1
您可能要这样做#define TRUE =(!(FALSE))
ant2009年

1
有什么好处#define TRUE = 1呢?
endlith 2012年

4
首先,不要在#define中放置等号(=)。其次,只有FALSE具有定义的值;零。TRUE是任何其他值。
鲍勃·韦克菲尔德

1

没有实际的速度差异。它们对于编译器实际上完全相同。不同之处在于人类试图使用和阅读您的代码。

对我来说,使bool,true和false成为C ++代码中的最佳选择。在C代码中,周围有一些不支持bool的编译器(我经常必须使用旧系统),因此在某些情况下我可以使用定义。


1

1最易读,并不兼容所有编译器。

没有ISO C编译器具有称为的内置类型bool。ISO C99编译器具有一个type_Bool和一个typedef的标头bool。因此,如果编译器不符合C99(例如VC ++),则兼容性只是提供您自己的标头的一种情况。

当然,更简单的方法是将C代码编译为C ++。


任何足够复杂的C代码都无法使用C ++编译器进行编译。如果要使用C ++编译器,请编写C ++代码。
klutt

@Broman我认为复杂性与它没有太大关系;语义上的细微差别。C ++更强大的类型检查将发出C编译不发出的问题诊断。在大多数情况下,可以解决这样的问题,并且使两种语言的代码有效且语义相同,并且在任何情况下,结果通常都是更好的代码。但是的确,大型(而不是复杂的)C代码库不太可能未经修改地进行编译。
克利福德,

没错,这不完全是复杂性。我的意思是,大多数不平凡的程序都将包含malloc调用,然后您需要进行强制转换。如果要使用C ++编译器进行编译,为什么不只编写C ++代码呢?
klutt

@Broman如果您编译为C ++,这是C ++,即使是同样有效C.使用malloc()和需要投的是一个实例,其中使C代码C ++的编译结果稍微恶化的C代码。
克利福德,

@Broman此外,这是一个非常古老的答案。到目前为止,VC ++具有更全面的C99支持,包括stdbool.h。除了C ++之外,实际上仅适用于C90,这越来越不可能了。
克利福德,

0

我更喜欢第三个解决方案,即使用1和0,因为它在必须测试条件是对还是错时特别有用:您可以简单地将变量用作if参数。
如果您使用其他方法,我认为,为了与其余代码保持一致,我应该使用这样的测试:

代替:


0

我更喜欢使用

或直接在代码中

编译器会解决这个问题。我使用多种语言,并且必须记住FALSE为0困扰着我很多。但是如果需要,我通常会考虑该字符串循环

这使我看到FALSE为0

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.