C没有任何内置的布尔类型。在C中使用它们的最佳方法是什么?
C没有任何内置的布尔类型。在C中使用它们的最佳方法是什么?
Answers:
从好到坏:
选项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!
<stdbool.h>
bool
,编译器选择的对齐方式,优化和存储方式可能更适合布尔值的预期用途int
(即,编译器选择的实现方式可能bool
不同于int
)。如果幸运的话,它还可能导致在编译时进行更严格的类型检查。
int
用于bool
?那太浪费了。使用unsigned char
。或使用C的buildin _Bool
。
关于C语言中布尔值的一些想法:
我已经够大了,我只使用plain int
s作为我的布尔类型,而没有任何类型定义或特殊定义或枚举来表示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
。
a == b
行不通吗?
a
和b
从零递增,我建议你a > 0 == b > 0
来代替。如果您坚持利用任意非零值的真实性,则会!!var
产生等于的布尔值0/1值var
,因此您可以编写!!a == !!b
,尽管很多读者会发现它令人困惑。
!a == !b
也足以测试相等性,非零变为零,零变为一。
!!a
为“将非布尔a转换为等效的真值”,而我读!a
为“逻辑上将布尔变量a求逆”。特别是,我会出于某些特定原因寻找逻辑反转。
这是我使用的版本:
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,
gcc -ansi -pedantic -Wall
没有给出警告,所以我相信gcc
; 如果这行得通,c89
它也应该行得通c99
。
!
只能返回0
和1
,因此true = !false
将始终分配值1。此方法不会给带来任何额外的安全性typedef enum { false, true } bool;
。
if(!value)
),编译器当然可以在法律上忽略此规则,但是该例外不适用于此特定情况。
如果使用的是C99编译器,则内置支持布尔类型:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
首先是第一件事。C,即ISO / IEC 9899,至今已有19年的布尔类型。这比访问该问题时将业余/学术/专业知识相结合的C编程职业的预期时间更长。我的确超过了大概1-2年。这意味着,在普通读者完全了解C的任何时间里,C实际上具有布尔数据类型。
对于数据类型,#include <stdbool.h>
和使用true
,false
和bool
。或不包括它和使用_Bool
,1
并0
代替。
此主题的其他答案中提出了各种危险做法。我将解决这些问题:
typedef int bool;
#define true 1
#define false 0
这是不对的,因为在19年内确实学习过C的随便的读者都希望bool
指的是实际的 bool
数据类型,并且行为类似,但是事实并非如此!例如
double a = ...;
bool b = a;
使用C99 bool
/时_Bool
,b
将被设置为false
iff a
为零,true
否则为零。C11 6.3.1.2p1
- 当任何标量值转换为时
_Bool
,如果值比较等于0,则结果为0;否则,结果为0。否则,结果为1。59)脚注
59)NaN不等于0,因此转换为1。
随着typedef
到位,double
将被强制转换为一个int
-如果双的值不在该范围int
时,行为未定义。
当然,如果true
和false
在中声明,enum
。
什么是甚至更危险的声明
typedef enum bool {
false, true
} bool;
因为现在除了1和0之外的所有值都是无效的,并且应该将此值分配给该类型的变量,则行为将是完全未定义的。
因此,当由于某些无法解释的原因而无法使用C99,则应使用布尔变量:
int
和值0
以及1
现状;并仔细进行域值从其他任何值到这些值的双重否定转换!!
BOOL
,TRUE
和FALSE
!int
或unsigned int
保留枚举的类型,但我不知道Standard中的任何内容会导致枚举除整数以外的行为类型。
typedef enum {
false = 0,
true
} t_bool;
!0 = 1
根据C标准,以及!a = 0
的任何非零值a
。问题是任何非零都被认为是真实的。因此,如果a
和b
均为“ true”,则不一定是`a == b`。
C具有布尔类型:bool(至少最近10(!)年)
包含stdbool.h和true / false将按预期工作。
bool
是一个扩展为的宏_Bool
。区别很重要,因为您可以#undef
使用宏(至少允许作为过渡措施),但不能untypedef
使用typedef。但是,它不会改变您的第一条评论的主旨。
在布尔运算中,任何非零值都将评估为true,因此您可以
#define TRUE 1
#define FALSE 0
并使用常量。
如果允许使用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
是:false
或true
。分配0
或1
代替false
或true
有效,但更难于阅读和理解逻辑流程。来自标准的一些信息:
_Bool
不是NOT unsigned int
,但属于组无符号整数类型。它足够大以容纳值0
或1
。bool
true
,false
但肯定不是个好主意。该功能被认为已过时,以后将被删除。_Bool
或bool
,如果标量值等于0
或比较0
它,则将标量类型(算术类型和指针类型)分配给或0
,否则结果是1
:分配给时将_Bool x = 9;
9
转换1
为x
。_Bool
是1字节(8位),通常程序员倾向于尝试使用其他位,但不建议这样做,因为给出的唯一保证是仅一位用于存储数据,而不像char
具有8位的类型位可用。如果条件表达式非零,则将其视为真,但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比较,无论如何都会触发警告。
如果使用的是C99,则可以使用该_Bool
类型。没有#include
必要。不过,您确实需要将其视为整数,其中1
is true
和0
is 在哪里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>
使用bool
,true
和,false
就像标准要求的那样。
您可以简单地使用以下#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);
等等
arg
和整个表达式之间加括号来保护#define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE)
。但是,最好测试一下是否正确(即使它arg
是23而不是0或1,它也会给出正确的答案#define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)
。但是整个表达式#define NOT(arg) (!(arg))
当然可以简化为,从而产生相同的结果。)