在C中使用布尔值


Answers:


1047

从好到坏:

选项1(C99)

#include <stdbool.h>

选项2

typedef enum { false, true } bool;

选项3

typedef int bool;
enum { false, true };

选项4

typedef int bool;
#define true 1
#define false 0

说明

  • 选项1仅在使用C99时才有效,这是“标准方式”。如果可能,请选择此选项。
  • 选项2、3和4实际上将具有相同的行为。#2和#3虽然没有使用#defines,但我认为更好。

如果您不确定,请选择#1!


1
您能否详细说明为什么它们是最好到最坏的选择?
endolith

1
@endolith与使用相比<stdbool.h> bool,编译器选择的对齐方式,优化和存储方式可能更适合布尔值的预期用途int(即,编译器选择的实现方式可能bool不同于int)。如果幸运的话,它还可能导致在编译时进行更严格的类型检查。
blubberdiblub

1
为什么int用于bool?那太浪费了。使用unsigned char。或使用C的buildin _Bool
无尸体

@NoBody使用较小的类型可以节省内存,但可能不会使其更快。通常情况下,它的速度更快使用处理器的原生字大小,而不是更小的尺寸,因为它可能需要编译器进行位移位以正确对齐
泰德·克莱恩伯格曼

240

关于C语言中布尔值的一些想法:

我已经够大了,我只使用plain ints作为我的布尔类型,而没有任何类型定义或特殊定义或枚举来表示true / false值。如果您遵循以下关于永远不要与布尔常量进行比较的建议,那么无论如何您只需要使用0/1来初始化标志。但是,在现代,这种方法可能被认为太反动了。在那种情况下,绝对应该使用,<stdbool.h>因为它至少具有标准化的好处。

无论调用什么布尔常量,都只能将它们用于初始化。从来没有写过像

if (ready == TRUE) ...
while (empty == FALSE) ...

这些总是可以用更清晰的代替

if (ready) ...
while (!empty) ...

请注意,这些实际上可以合理且可以理解地大声读出。

给您的布尔变量一个正名称,即full而不是notfull。后者导致难以阅读的代码。相比

if (full) ...
if (!full) ...

if (!notfull) ...
if (notfull) ...

前一对都自然阅读,而!notfull即使原样阅读也很尴尬,并且在更复杂的布尔表达式中变得更糟。

通常应避免布尔参数。考虑这样定义的函数

void foo(bool option) { ... }

在函数的主体内,参数很清楚,因为该参数具有方便且希望有意义的名称。但是,呼叫站点看起来像

foo(TRUE);
foo(FALSE):

在这里,从不总是查看函数定义或声明就根本不可能知道参数的含义,并且如果添加更多的布尔参数,情况将变得更加糟糕。我建议

typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);

要么

#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }

无论哪种情况,呼叫站点现在看起来都像

foo(OPT_ON);
foo(OPT_OFF);

读者至少有机会理解而不弄清楚的定义foo


1
您如何比较两个变量的相等性?永远不要使用布尔常量会很好,但是与非常量比较时,它不能解决问题。
Baruch 2014年

原谅我,但我不明白这个问题。您是否在问我如何比较两个布尔变量的相等性?如果是这样,那a == b行不通吗?
Dale Hagglund 2014年

5
@Kenji您所说的是正确的,尽管我认为使用非1的值等效为true几乎总是一个坏主意。因此,在你的例子,假设 ab从零递增,我建议你a > 0 == b > 0来代替。如果您坚持利用任意非零值的真实性,则会!!var产生等于的布尔值0/1值var,因此您可以编写!!a == !!b,尽管很多读者会发现它令人困惑。
Dale Hagglund 2015年

3
!a == !b也足以测试相等性,非零变为零,零变为一。
ryanpattison

5
@rpattiso当然,您说的很对,但是我想我会读!!a为“将非布尔a转换为等效的真值”,而我读!a为“逻辑上将布尔变量a求逆”。特别是,我会出于某些特定原因寻找逻辑反转。
Dale Hagglund


74

这是我使用的版本:

typedef enum { false = 0, true = !false } bool;

因为false仅具有一个值,但是逻辑true可能具有多个值,但是技术将true设置为编译器将用于false的相反对象。

这可以解决有人编码的问题:

if (true == !false)

我认为我们都同意这不是一个好习惯,但是一次做“ true =!false”的成本我们消除了这个问题。

[编辑]最后,我使用了:

typedef enum { myfalse = 0, mytrue = !myfalse } mybool;

避免名称与定义true和的其他方案冲突false。但是概念保持不变。

[EDIT]显示整数到布尔值的转换:

mybool somebool;
int someint = 5;
somebool = !!someint;

第一个(最右边)!将非零整数转换为0,然后转换为第二个(最左侧)!将0转换为myfalse值。我将其保留为读者练习转换零整数的练习。

[编辑]我的风格是在需要特定值的情况下使用枚举中值的显式设置,即使默认值相同。示例:因为false需要为零,所以我使用false = 0,而不是false,


5
使用枚举的另一个好处是IDE集成- truefalse并且bool在大多数IDE中都被突出显示,因为它们是枚举值和typedef(与相对)#defines,而语法很少被突出显示。

好奇:忽略它是否实际有效,是否允许C(99+)允许枚举引用同一枚举中的先前值?

@ tgm1024 gcc -ansi -pedantic -Wall没有给出警告,所以我相信gcc; 如果这行得通,c89它也应该行得通c99
yyny

1
“因为false仅具有一个值,但是逻辑true可能具有许多值,但是技术将true设置为编译器将用于false的反面。” 取反运算符!只能返回01,因此true = !false将始终分配值1。此方法不会给带来任何额外的安全性typedef enum { false, true } bool;
user694733 '19

1
我最早发现的是C90(6.3.3.3一元算术运算符):“如果逻辑运算符的操作数的值不等于0,则逻辑取反运算符!的结果为0。如果其运算数的值等于0,则为1。结果的类型为int。表达式!E等效于(O == E)。这应该涵盖曾经声称支持标准C的所有编译器。在对于可观察到的行为无关紧要的情况下(例如if(!value)),编译器当然可以在法律上忽略此规则,但是该例外不适用于此特定情况。
user694733'9


30

首先是第一件事。C,即ISO / IEC 9899,至今已有19年的布尔类型。这比访问该问题时将业余/学术/专业知识相结合的C编程职业的预期时间更长。我的确超过了大概1-2年。这意味着,在普通读者完全了解C的任何时间里,C实际上具有布尔数据类型

对于数据类型,#include <stdbool.h>和使用truefalsebool。或不包括它和使用_Bool10代替。


此主题的其他答案中提出了各种危险做法。我将解决这些问题:

typedef int bool;
#define true 1
#define false 0

这是不对的,因为在19年内确实学习过C的随便的读者都希望bool指的是实际的 bool数据类型,并且行为类似,但是事实并非如此!例如

double a = ...;
bool b = a;

使用C99 bool/时_Boolb将被设置为false iff a为零,true否则为零。C11 6.3.1.2p1

  1. 当任何标量值转换为时_Bool,如果值比较等于0,则结果为0;否则,结果为0。否则,结果为1。59)

脚注

59)NaN不等于0,因此转换为1。

随着typedef到位,double将被强制转换为一个int-如果双的值不在该范围int时,行为未定义

当然,如果truefalse在中声明,enum

什么是甚至更危险的声明

typedef enum bool {
    false, true
} bool;

因为现在除了1和0之外的所有值都是无效的,并且应该将此值分配给该类型的变量,则行为将是完全未定义的

因此,由于某些无法解释的原因而无法使用C99,则应使用布尔变量:

  • 类型int和值0以及1 现状;并仔细进行域值从其他任何值到这些值的双重否定转换!!
  • 或者,如果你坚持,你不记得0 falsy和非零truish,至少用大写,让他们不要混淆与C99概念:BOOLTRUEFALSE

1
C标准的哪一部分将枚举类型的对象限制为保留其中明确列出的值?如果枚举常量的最大值小于UCHAR_MAX或USHRT_MAX,则实现可以使用小于intunsigned int保留枚举的类型,但我不知道Standard中的任何内容会导致枚举除整数以外的行为类型。
超级猫

18
typedef enum {
    false = 0,
    true
} t_bool;

2
2到MAX_INT也应评估为真
Technosaurus

2
@technosaurus使用此方法不能保证!false == true,因为!false可以是任何非零数字。一个简单的解决方法是将true明确分配给!false。
安德鲁(Andrew)

3
@安德鲁这不是真的。!0 = 1根据C标准,以及!a = 0的任何非零值a。问题是任何非零都被认为是真实的。因此,如果ab均为“ true”,则不一定是`a == b`。
杰里米·韦斯特

14

C具有布尔类型:bool(至少最近10(!)年)

包含stdbool.h和true / false将按预期工作。


12
标准是10年,而编译器不是10年!MSVC ++的C编译除了允许//注释外,根本不支持C99,而且也不太可能这样做。_Bool在C99中也定义为内置类型,而bool是<stdbool.h>头中的typedef。
克利福德,

5
@Clifford,距离您发表评论已有4年了……一切都没有改变。MSVC是C ++编译器,我相信MS曾经说过,他们并不真的热衷于支持所有新的C功能(C99和C11)。但是我不能认为MSVC不支持新的C功能是有原因的(尤其是当您回答10年后才说出来)。在编程世界中10年确实是很长的时间。如果供应商打算支持它,那么任何体面的编译器都应在不到10年的时间内获得支持。
PP

2
@KingsIndian:我不确定您为什么向我直接发表评论,甚至根本不需要发表评论。我仅是在撰写本文时说明情况。我不支持这种情况,只是指出“答案”可能不适用于所有情况。
克利福德

@Clifford:严格来说,标准要求bool是一个扩展为的宏_Bool。区别很重要,因为您可以#undef使用宏(至少允许作为过渡措施),但不能untypedef使用typedef。但是,它不会改变您的第一条评论的主旨。
乔纳森·莱夫勒

2
VS2015,后来(可能更早,到一个点)都没有问题bool,通过<stdbool.h>在C编译。解析为_Bool

11

在布尔运算中,任何非零值都将评估为true,因此您可以

#define TRUE 1
#define FALSE 0

并使用常量。


10
但要小心使用:由于真实结果可能是任何非零值,因此在其他语言中等效的测试if(t == TRUE){...}和if(t)在C语言中不等效。
Fortega

1
您是对的,但是在具有bool类型的C ++中也是如此,对吗?在调试过程中,我看到了布尔变量,其值为5837834939 ...
ggambett

1
在C ++中,if(t == true)测试等于if(t)测试,因为C ++进行了一些转换(所有不为0或空指针值都转换为true的转换)
Fortega

6
关于布尔真值,您应该假设的是它非零。因此,像if(b)这样的代码是安全的,而if(b == TRUE)则不是;后者是不好的做法(毫无意义)。
克利福德,

5

如果允许使用C99,则仅是对其他答案和澄清的补充。

+-------+----------------+-------------------------+--------------------+
|  Name | Characteristic | Dependence in stdbool.h |        Value       |
+-------+----------------+-------------------------+--------------------+
| _Bool |   Native type  |    Don't need header    |                    |
+-------+----------------+-------------------------+--------------------+
|  bool |      Macro     |           Yes           | Translate to _Bool |
+-------+----------------+-------------------------+--------------------+
|  true |      Macro     |           Yes           |   Translate to 1   |
+-------+----------------+-------------------------+--------------------+
| false |      Macro     |           Yes           |   Translate to 0   |
+-------+----------------+-------------------------+--------------------+

我的一些偏好:

  • _Bool还是bool?两者都很好,但是bool看起来比关键字更好_Bool
  • 为接受的价值观bool_Bool是:falsetrue。分配01代替falsetrue有效,但更难于阅读和理解逻辑流程。

来自标准的一些信息:

  • _Bool不是NOT unsigned int,但属于组无符号整数类型。它足够大以容纳值01
  • 不能,但是可以,您可以重新定义bool truefalse但肯定不是个好主意。该功能被认为已过时,以后将被删除。
  • 标量类型(算术类型和指针类型)分配给_Boolbool,如果量值等于0或比较0它,则将标量类型(算术类型和指针类型)分配给或0,否则结果是1:分配给时将_Bool x = 9; 9转换1x
  • _Bool是1字节(8位),通常程序员倾向于尝试使用其他位,但不建议这样做,因为给出的唯一保证是仅一位用于存储数据,而不像char具有8位的类型位可用。


2

您可以使用char或其他少量容器。

伪码

#define TRUE  1
#define FALSE 0

char bValue = TRUE;

此外,在C中,它通常是一个int,它可以通过其他代码造成精密警告的损失以Int ...
托马斯博尼尼

除非您手动优化空间,否则最好使用硬件的常规字长(例如:通常为int),因为在某些体系结构上,您必须对这些变量进行解包/掩码检查会显着降低性能。
金斯利

2

您可以使用_Bool,但是返回值必须是整数(1表示true,0表示false)。但是,它的建议,包括与使用布尔在C ++中,在说 这个回答来自daniweb论坛,以及这个答案,从这个计算器的其他问题:

_Bool:C99的布尔类型。仅当您要维护已为bool,true或false定义宏的旧代码时,才建议直接使用_Bool。否则,这些宏将在标头中标准化。包含该标头,就可以像在C ++中一样使用bool。


2

如果条件表达式非零,则将其视为真,但C标准要求逻辑运算符本身返回0或1。

@Tom:#define TRUE!FALSE不好,而且毫无意义。如果头文件进入编译的C ++代码,则可能导致问题:

void foo(bool flag);

...

int flag = TRUE;
foo(flag);

一些编译器会生成有关int => bool转换的警告。有时人们通过执行以下操作来避免这种情况:

foo(flag == TRUE);

将表达式强制为C ++ bool。但是,如果您#define TRUE!FALSE,您将得到:

foo(flag == !0);

最后进行int-to-bool比较,无论如何都会触发警告。


1

如果使用的是C99,则可以使用该_Bool类型。没有#include必要。不过,您确实需要将其视为整数,其中1is true0is 在哪里false

然后TRUE,您可以定义和FALSE

_Bool this_is_a_Boolean_var = 1;


//or using it with true and false
#define TRUE 1
#define FALSE 0
_Bool var = TRUE;

或者,您可以#include <stdbool.h>使用booltrue和,false就像标准要求的那样。
SS安妮

1

如今,C99支持布尔类型,但您需要这样做#include <stdbool.h>

例:

#include <stdbool.h>

int main() 
{ 
    bool arr[2] = {true, false}; 

    printf("%d\n", arr[0] && arr[1]);
    printf("%d\n", arr[0] || arr[1]);

    return 0; 
} 

输出:

0
1

0

这是我用的:

enum {false, true};
typedef _Bool bool;

_Bool 是C语言中的内置类型。它用于布尔值。


-2

您可以简单地使用以下#define指令:

#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;

并使用如下:

bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);

等等


5
NOT宏应该在arg和整个表达式之间加括号来保护#define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE)。但是,最好测试一下是否正确(即使它arg是23而不是0或1,它也会给出正确的答案#define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)。但是整个表达式#define NOT(arg) (!(arg))当然可以简化为,从而产生相同的结果。)
Jonathan Leffler
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.