【发布时间】:2010-12-27 15:37:37
【问题描述】:
C 没有任何内置的布尔类型。在 C 中使用它们的最佳方式是什么?
【问题讨论】:
-
C 确实有布尔类型。最新的标准中至少有一个。
C 没有任何内置的布尔类型。在 C 中使用它们的最佳方式是什么?
【问题讨论】:
任何非零值在布尔运算中都被评估为真,所以你可以
#define TRUE 1
#define FALSE 0
并使用常量。
【讨论】:
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
如果您还没有决定,请选择#1!
【讨论】:
<stdbool.h> bool 的方式可能比使用int 更适合布尔值的预期目的(即编译器可以选择以不同于int 的方式实现bool)。如果幸运的话,它还可能导致在编译时进行更严格的类型检查。
int 用于bool?那很浪费。使用unsigned char。或者使用C的内置_Bool。
<stdbool.h> 不同。例如,它们不满足(bool)(13 & 8) == true。对于选项 2-4,您必须改写 !!(13 & 8) == true。这一直出现在位域测试中……想想一个返回 (13 & 8) 且返回类型为 bool 的宏。
您可以使用 char 或其他小数字容器。
伪代码
#define TRUE 1
#define FALSE 0
char bValue = TRUE;
【讨论】:
int),因为在某些架构上,您会因为拥有解压/屏蔽对这些变量的检查。
是这样的:
#define TRUE 1
#define FALSE 0
【讨论】:
typedef enum {
false = 0,
true
} t_bool;
【讨论】:
!0 = 1 按 C 标准,!a = 0 表示 a 的任何非零值。问题是任何非零都被认为是真实的。因此,如果a 和b 都是“真”,则不一定是`a == b`。
C 有一个布尔类型:bool(至少在过去 10(!) 年)
包含 stdbool.h 和 true/false 将按预期工作。
【讨论】:
bool 是扩展为_Bool 的宏。区别很重要,因为您可以#undef 宏(这是允许的,至少作为过渡措施),但您不能untypedef 类型定义。不过,它不会改变您第一条评论的主旨。
bool 到 <stdbool.h> 没有问题。它解析为_Bool。
如果您使用的是 C99 编译器,它内置了对 bool 类型的支持:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
【讨论】:
stdbool.h 中进行类型定义,因此您在包含文件中包含typedef enum {false, true} bool;
_Bool 的内置类型。它不是枚举。 bool、true 和 false 是在 <stdbool.h> 中定义的宏,它们分别扩展为 _Bool、1 和 0。见en.cppreference.com/w/c/types/boolean
如果条件表达式不为零,则认为它们为真,但 C 标准要求逻辑运算符本身返回 0 或 1。
@Tom:#define TRUE !FALSE 不好,完全没有意义。如果头文件进入已编译的 C++ 代码,则可能会导致问题:
void foo(bool flag);
...
int flag = TRUE;
foo(flag);
某些编译器会生成有关 int => bool 转换的警告。有时人们会通过这样做来避免这种情况:
foo(flag == TRUE);
强制表达式为 C++ 布尔值。但是如果你#define TRUE !FALSE,你最终会得到:
foo(flag == !0);
最终会进行 int-to-bool 比较,无论如何都会触发警告。
【讨论】:
关于 C 中布尔值的一些想法:
我已经足够大了,我只使用普通的ints 作为我的布尔类型,没有任何类型定义或特殊定义或真/假值的枚举。如果您按照我下面的建议从不与布尔常量进行比较,那么您只需要使用 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 会产生与var 等价的布尔值 0/1,所以你可以写成!!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 的其他方案发生名称冲突。但概念保持不变。
[编辑] 显示整数到布尔值的转换:
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 个字节。
【讨论】:
true、false 和 bool 在大多数 IDE 中突出显示,因为它们是枚举值和 typedef,而不是 #defines , 很少会突出显示语法。
! 只能返回值0 和1,因此true = !false 将始终分配值1。这种方法不会比typedef enum { false, true } bool; 提供任何额外的安全性。
if(!value))当然可以合法地忽略此规则,但该例外不适用于这种特定情况。
您可以简单地使用#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)),这产生相同的结果。
首先要做的事情。 C,即 ISO/IEC 9899 的布尔类型已有 19 年。这比访问 this question 时的 expected 业余/学术/专业部分的 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;否则,结果为 1. 59)脚注
59) NaN 比较不等于 0,因此转换为 1。
使用typedef,double 将被强制转换为int - 如果双精度值不在int 的范围内,则行为未定义强>。
如果true 和false 在enum 中声明,自然同样适用。
更更危险的是声明
typedef enum bool {
false, true
} bool;
因为现在除了 1 和 0 之外的所有值都是无效的,如果将这样的值分配给该类型的变量,行为将完全未定义。
因此iff由于某些莫名其妙的原因,您不能使用 C99,对于布尔变量,您应该使用:
int 和值0 和1 原样;并小心地将任何其他值的域转换为双重否定!!
BOOL、TRUE 和 FALSE!【讨论】:
int 或 unsigned int 的类型来保存枚举,但我不知道标准中会导致枚举行为作为整数类型以外的任何东西。
如果您被允许使用 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 不是unsigned int,而是无符号整数类型组的一部分。它足够大,可以容纳 0 或 1 的值。bool true 和 false 但肯定不是一个好主意。此功能已过时,将来会被移除。0 或与0 将是0,否则结果是1:_Bool x = 9; 9 分配给1 时转换为1。_Bool 是 1 字节(8 位),通常程序员很想尝试使用其他位,但不推荐使用,因为唯一保证的是只使用一位来存储数据,而不是像 type char 有 8 位可用。【讨论】:
您可以使用 _Bool,但返回值必须是整数(1 表示真,0 表示假)。 但是,建议在 C++ 中包含和使用 bool,如 this reply 来自daniweb forum,以及this answer,来自另一个stackoverflow 问题:
_Bool:C99 的布尔类型。仅当您维护已经为 bool、true 或 false 定义宏的遗留代码时,才建议直接使用 _Bool。否则,这些宏将在标头中标准化。包含该标头,您可以像在 C++ 中一样使用 bool。
【讨论】:
如果您使用的是 C99,那么您可以使用 _Bool 类型。不需要#includes。不过,您确实需要将其视为整数,其中 1 是 true 而0 是 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。
现在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
【讨论】:
这是我用的:
enum {false, true};
typedef _Bool bool;
_Bool 是 C 中的内置类型。它用于布尔值。
【讨论】: