C没有任何内置布尔类型。在C语言中使用它们的最佳方式是什么?
从好到坏:
选项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
解释
只有当你使用C99(或更高版本)时,选项1才会起作用,这是“标准方式”。如果可能,请选择此选项。选项2、3和4实际上具有相同的行为#2和#3不使用#defines,我认为这更好。
如果你还没有决定,那就选择#1!
如果您使用的是C99编译器,它内置了对布尔类型的支持:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
http://en.wikipedia.org/wiki/Boolean_data_type
如果条件表达式为非零,则认为它们为真,但C标准要求逻辑运算符本身返回0或1。
@汤姆:#定义正确!FALSE是糟糕的,完全没有意义。如果头文件进入编译的C++代码,那么它可能会导致问题:
void foo(bool flag);
...
int flag = TRUE;
foo(flag);
某些编译器会生成关于int=>bool转换的警告。有时人们会通过以下方式避免这种情况:
foo(flag == TRUE);
以强制表达式为C++布尔值。但如果你#定义TRUE!如果为FALSE,则结果为:
foo(flag == !0);
它最终会进行int到bool的比较,这无论如何都会触发警告。
关于C中布尔值的几点思考:
我已经足够老了,我只使用纯int作为布尔类型,没有任何typedef或true/false值的特殊定义或枚举。如果你遵循我下面的建议,不要与布尔常量进行比较,那么你只需要使用0/1来初始化标志。然而,这种方法在现代可能被认为过于反动。在这种情况下,肯定应该使用<stdbool.h>,因为它至少有标准化的好处。
无论调用什么布尔常量,都只能用于初始化。永远不要写类似的东西
if (ready == TRUE) ...
while (empty == FALSE) ...
这些总是可以被更清晰的
if (ready) ...
while (!empty) ...
请注意,这些事实上可以合理且可以理解地大声读出。
给布尔变量取正名,即full而不是notfull。后者导致代码难以容易阅读。比较
if (full) ...
if (!full) ...
with
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);
or
#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }
无论哪种情况,呼叫站点现在看起来都是
foo(OPT_ON);
foo(OPT_OFF);
读者至少有机会在不理解foo定义的情况下理解它。
以下是我使用的版本:
typedef enum { false = 0, true = !false } bool;
因为false只有一个值,但逻辑true可以有多个值,但是技术将true设置为编译器将使用的与false相反的值。
这解决了某些人编码的问题,这些问题可以归结为:
if (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编译时限制枚举的大小:
typedef __attribute__((__packed__)) enum { myfalse = 0, mytrue = !myfalse } mybool;
也就是说,如果有人这样做:
struct mystruct {
mybool somebool1;
mybool somebool2;
mybool somebool3;
mybool somebool4;
}
结构的大小将是4字节而不是16字节。
您可以简单地使用#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);
等等
第一件事。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,如果a为零,b将设置为false,否则为true。C11 6.3.1.2p1
当任何标量值转换为_Bool时,如果值比较等于0,则结果为0;否则,结果为1。59)脚注59)NaN不等于0,因此转换为1。
在typedef就位的情况下,double将被强制为int-如果double的值不在int的范围内,则行为未定义。
当然,如果在枚举中声明了true和false,这同样适用。
更危险的是宣布
typedef enum bool {
false, true
} bool;
因为现在除了1和0之外的所有值都是无效的,如果将这样的值分配给该类型的变量,则行为将完全未定义。
因此,如果有某种莫名其妙的原因,如果您不能使用C99,则应使用布尔变量:
按原样键入int和值0和1;并小心地将域从任何其他值转换为带有双重否定的值!!或者如果你坚持认为你不记得0是假的和非零真的,那么至少使用大写,这样他们就不会与C99的概念混淆:BOOL、TRUE和FALSE!
如果允许您使用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的接受值为:false或true。指定0或1而不是false或true是有效的,但更难阅读和理解逻辑流。
标准中的一些信息:
_Bool不是无符号整数,而是无符号整数类型组的一部分。它足够大,可以保存值0或1。不要,但是的,你可以重新定义bool true和false,但肯定不是个好主意。这种能力被认为是过时的,将来将被删除。将标量类型(算术类型和指针类型)赋给_Bool或Bool,如果标量值等于0或与0比较,则为0,否则结果为1:_Bool x=9;当分配给x时,9被转换为1。_Bool是1字节(8位),通常程序员会尝试使用其他位,但不建议使用,因为唯一的保证是只使用一位来存储数据,而不是像具有8位可用的类型字符那样。
可以使用_Bool,但返回值必须是整数(1表示真,0表示假)。但是,建议在C++中包含和使用bool,如中所述这个来自daniweb论坛的回答,以及来自另一个stackoverflow问题的回答:
_布尔:C99的布尔类型。只有在维护已经为Bool、true或false定义宏的遗留代码时,才建议直接使用_Bool。否则,这些宏将在标题中标准化。包含该标头,您可以像在C++中一样使用bool。
如果使用C99,则可以使用_Bool类型。不需要#includes。不过,您确实需要将其视为整数,其中1为真,0为假。
然后可以定义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;
现在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