在C中使用布尔值

neu*_*cer 659 c boolean

C没有任何内置布尔类型.在C中使用它们的最佳方法是什么?

Tho*_*ini 996

从最好到更糟:

选项1(C99)

#include <stdbool.h>
Run Code Online (Sandbox Code Playgroud)

选项2

typedef enum { false, true } bool;
Run Code Online (Sandbox Code Playgroud)

选项3

typedef int bool;
enum { false, true };
Run Code Online (Sandbox Code Playgroud)

选项4

typedef int bool;
#define true 1
#define false 0
Run Code Online (Sandbox Code Playgroud)

说明

  • 选项1仅在您使用C99时才有效,并且它是执行此操作的"标准方式".如果可能请选择此项.
  • 选项2,3和4在实践中将具有相同的相同行为.#2和#3不使用#defines,在我看来更好.

如果你还未决定,请选择#1!

  • 您能详细说明“为什么”它们是最好到最差的选择吗? (8认同)
  • @endolith编译器选择的对齐、优化和存储“&lt;stdbool.h&gt;”“bool”的方式可能比利用“int”更适合布尔值的预期目的(即编译器可能选择实现“bool”与“int”不同)。如果幸运的话,它还可能导致在编译时进行更严格的类型检查。 (7认同)
  • 选项 2-4 的行为与“&lt;stdbool.h&gt;”不同。例如,它们不满足“(bool)(13 &amp; 8) == true”。对于选项 2-4,您必须改为编写 `!!(13 &amp; 8) == true`。这在位域测试中总是出现......想想一个返回“(13 &amp; 8)”且返回类型为“bool”的宏。 (6认同)
  • 为什么使用“int”作为“bool”?那太浪费了。使用“无符号字符”。或者使用 C 的内置 `_Bool`。 (2认同)
  • @NoBody 使用较小的类型可以节省内存,但可能不会使其更快。通常,使用处理器的本机字大小而不是较小的字大小会更快,因为它可能需要编译器进行位移以正确对齐它 (2认同)
  • 另外,`_Bool x = 0.5;printf("%d", x);` 将输出 `1` 而 `int x = 0.5; printf("%d", x);` 将输出 0。 (2认同)

Dal*_*und 231

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

我已经够老了,我只使用plain ints作为我的布尔类型,没有任何typedef或特殊定义或枚举的真/假值.如果您按照我的建议从不与布尔常量进行比较,那么您只需要使用0/1来初始化标志.然而,在这些现代时代,这种方法可能被认为过于反动.在这种情况下,一定要使用,<stdbool.h>因为它至少具有标准化的好处.

无论调用什么布尔常量,只能将它们用于初始化.永远不要写像

if (ready == TRUE) ...
while (empty == FALSE) ...
Run Code Online (Sandbox Code Playgroud)

这些总是可以被清除者取代

if (ready) ...
while (!empty) ...
Run Code Online (Sandbox Code Playgroud)

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

给你的布尔变量正名,即full代替notfull.后者导致代码难以阅读.相比

if (full) ...
if (!full) ...
Run Code Online (Sandbox Code Playgroud)

if (!notfull) ...
if (notfull) ...
Run Code Online (Sandbox Code Playgroud)

前两对都是自然读取的,虽然!notfull它很难读,但在更复杂的布尔表达式中变得更糟.

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

void foo(bool option) { ... }
Run Code Online (Sandbox Code Playgroud)

在函数体内,非常清楚参数的含义,因为它具有方便且有希望的有意义的名称.但是,呼叫网站看起来像

foo(TRUE);
foo(FALSE):
Run Code Online (Sandbox Code Playgroud)

在这里,基本上不可能在不总是查看函数定义或声明的情况下告诉参数意味着什么,如果添加更多的布尔参数,它会变得更糟.我建议

typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);
Run Code Online (Sandbox Code Playgroud)

要么

#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }
Run Code Online (Sandbox Code Playgroud)

在任何一种情况下,呼叫站点现在看起来像

foo(OPT_ON);
foo(OPT_OFF);
Run Code Online (Sandbox Code Playgroud)

读者至少有机会理解而不需要挖掘定义foo.

  • 请原谅我,但我不明白这个问题。您是在问我如何比较两个布尔变量是否相等?如果是这样,那么 `a == b` 不起作用吗? (4认同)
  • @Kenji你说的是真的,虽然我认为使用除了一个以外的值等同于真值几乎总是一个坏主意.所以在你的例子中,假设`a`和`b'从零开始计数,我建议改为使用`a> 0 == b> 0`.如果你坚持利用任意非零值的真实性,`!! var`产生相当于`var`的布尔值0/1,所以你可以写`!! a == !! b`,虽然不少读者会发现它令人困惑. (4认同)
  • @rpattiso当然,你是对的,但我想我会把`!! a`看作"将非布尔a转换成它的等价真值",而我会把`!a`看作是"逻辑上颠倒了布尔变量a".特别是,我会寻找一些需要逻辑反转的具体原因. (3认同)
  • `!a ==!b`也足以测试相等性,非零变为零,零成为一. (2认同)
  • “请注意,这些实际上可以合理且易于理解地大声朗读。” 这可能是我迄今为止读过的所有 StackOverflow 答案中最有用的建议。一般来说,代码的可读性是一个严重的问题。 (2认同)

For*_*ega 83

C中的布尔值是一个整数:零表示假,非零表示真.

另请参见布尔数据类型,C,C++,Objective-C,AWK.


Mic*_*ter 72

这是我使用的版本:

typedef enum { false = 0, true = !false } bool;
Run Code Online (Sandbox Code Playgroud)

因为false只有一个值,但逻辑true可以有很多值,但是技术设置为true,编译器将使用与false相反的值.

这解决了某人编写某些内容的问题:

if (true == !false)
Run Code Online (Sandbox Code Playgroud)

我想我们都同意这不是一个好的做法,但是对于做"真=假"的一次性成本我们消除了这个问题.

[编辑]最后我用过:

typedef enum { myfalse = 0, mytrue = !myfalse } mybool;
Run Code Online (Sandbox Code Playgroud)

避免与定义true和定义的其他方案发生名称冲突false.但这个概念仍然是一样的.

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

mybool somebool;
int someint = 5;
somebool = !!someint;
Run Code Online (Sandbox Code Playgroud)

第一个(最右边)!将非零整数转换为0,然后是第二个(最左边)!将0转换为myfalse值.我将把它作为练习让读者转换零整数.

  • 使用枚举的另一个好处是IDE集成 - 在大多数IDE中突出显示`true`,`false`和`bool`,因为它们是枚举值和typedef,而不是`#simic`,它们很少被突出显示语法. (4认同)
  • *“因为 false 只有一个值,但逻辑 true 可以有多个值,但技术将 true 设置为编译器将用于与 false 相反的值。”* 否定运算符 `!` 只能返回值 `0` 和`1`,因此 `true = !false` 将始终分配值 1。此方法不会比 `typedef enum { false, true } bool;` 提供任何额外的安全性。 (3认同)
  • 我最早发现的是来自 C90(6.3.3.3 一元算术运算符): *“如果其操作数的值比较不等于 0,则逻辑非运算符 ! 的结果为 0。如果其操作数的值比较等于 0,则结​​果为 1。结果的类型为 int。表达式 !E 相当于 (O==E)。"* 这应该涵盖任何曾经声称支持标准 C 的编译器。在不支持标准 C 的情况下,编译器当然可以合法地忽略此规则对于可观察的行为(如“if(!value)”)并不重要,但该异常在这种特定情况下不适用。 (2认同)

Gar*_*hby 46

如果您使用的是C99编译器,它内置了对bool类型的支持:

#include <stdbool.h>
int main()
{
  bool b = false;
  b = true;
}
Run Code Online (Sandbox Code Playgroud)

http://en.wikipedia.org/wiki/Boolean_data_type

  • @JamesStevens 这是不对的。有一个名为“_Bool”的内置类型。它不是一个枚举。“bool”、“true”和“false”是在“&lt;stdbool.h&gt;”中定义的宏,分别扩展为“_Bool”、“1”和“0”。请参阅 https://en.cppreference.com/w/c/types/boolean (2认同)

Ant*_*ala 24

首先要做的事情.C,即ISO/IEC 9899已有19年的布尔类型.在访问这个问题时,比在业余/学术/专业部分结合的C编程职业的预期时间长得多.我的确超过了大概1 - 2年.这意味着在普通读者完全学习C语言的过程中,C实际上具有布尔数据类型.

对于数据类型,#include <stdbool.h>和使用true,falsebool.或不包括它,使用_Bool,10来代替.


这个答案帖中有各种危险的建议.我会解决他们:

typedef int bool;
#define true 1
#define false 0
Run Code Online (Sandbox Code Playgroud)

这是禁忌,因为一个随便的读者 - 在这19年内确实学过C - 会期望它bool指的是实际的 bool数据类型,并且行为类似,但事实并非如此!例如

double a = ...;
bool b = a;
Run Code Online (Sandbox Code Playgroud)

使用C99 bool/时_Bool,b将设置为false iff a为零,true否则.随着typedef到位,double将被强制转换为一个int-如果双重的价值不在该范围内int,该行为是不确定的.

当然,同样适用于if truefalse被声明的enum.

宣告更危险的是什么

typedef enum bool {
    false, true
} bool;
Run Code Online (Sandbox Code Playgroud)

因为现在除了1和0之外的所有值都是无效的,并且如果将这样的值赋给该类型的变量,则行为将完全未定义.

因此,如果您因某些无法解释的原因无法使用C99,那么对于布尔变量,您应该使用:

  • 类型int和值0以及1 原样 ; 并通过双重否定小心地将域转换从任何其他值转换为这些值!!
  • 或者,如果你坚持,你不记得0 falsy和非零truish,至少要用大写字母,让他们不要混淆与C99概念:BOOL,TRUEFALSE!

  • C 标准的哪一部分将限制枚举类型的对象保存其中明确列出的值?如果枚举常量的最大值小于 UCHAR_MAX 或 USHRT_MAX,则实现可以使用小于 `int` 或 `unsigned int` 的类型来保存枚举,但我不知道标准中的任何内容会导致枚举表现得像整数类型以外的任何东西。 (2认同)

mou*_*iel 18

typedef enum {
    false = 0,
    true
} t_bool;
Run Code Online (Sandbox Code Playgroud)

  • @Andrew 那不是真的。`!0 = 1` 按照 C 标准,`!a = 0` 表示 `a` 的任何非零值。问题是任何非零都被认为是真的。因此,如果`a` 和`b` 都为“真”,则`a == b` 不一定是这种情况。 (3认同)
  • 通过MAX_INT 2也应评估为true (2认同)
  • @technosaurus使用此方法不能保证!false == true,因为!false可以是任何非零数字。一个简单的解决方法是将true明确分配给!false。 (2认同)

dme*_*ter 13

C有一个布尔类型:bool(至少在最后10(!)年)

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

  • 10年的标准,但不是10年的编译器!MSVC++的C编译除了允许//注释之外不支持C99,并且不可能这样做.另外_Bool在C99中定义为内置类型,而bool是<stdbool.h>头中的typedef. (11认同)
  • @Clifford自你评论4年后......没有任何改变.MSVC是一个C++编译器,我相信MS已经表示他们并不真正热衷于支持所有新的C功能(C99和C11).但我不能认为MSVC不支持新的C功能作为一个原因(特别是当你说*10年*答案时).在编程领域,10年真的是一段很长的时间.如果供应商打算支持它,那么任何体面的编译器都应该在不到10年的时间内为它提供支持. (4认同)
  • @KingsIndian:我不确定你为什么把评论发给我,甚至觉得有必要发表评论.我只是陈述了写作时的情况.我并不支持这种情况,只是指出"答案"可能并不适用于所有情况. (2认同)
  • VS2015 及更高版本(可能更早,在某种程度上)在 C 编译下通过 `&lt;stdbool.h&gt;` 使用 `bool` 没有问题。它解析为`_Bool`。 (2认同)

gga*_*ett 10

在布尔运算中,任何非零值都会被计算为true,所以你可以这样做

#define TRUE 1
#define FALSE 0
Run Code Online (Sandbox Code Playgroud)

并使用常量.

  • 但要小心使用它们:因为真实的结果可能是任何非零值,所以测试if(t == TRUE){...}和if(t)在其他语言中是等价的,在C中是不相等的. (10认同)
  • 你应该假设一个布尔值为零,它是非零的.因此if(b)之类的代码是安全的,而if(b == TRUE)则不是; 后者是不好的做法(而且毫无意义). (5认同)
  • 你是对的,但在 C++ 中也是如此,它确实有 bool 类型,对吗?在调试过程中,我看到 bool 变量的值为 5837834939... (2认同)

Und*_*ior 6

如果您被允许使用 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   |
+-------+----------------+-------------------------+--------------------+
Run Code Online (Sandbox Code Playgroud)

我的一些偏好:

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

来自标准的一些信息:

  • _Bool不是unsigned int,而是无符号整数类型组的一部分。它足够大以保存值0or 1
  • 不要,但是是的,您可以重新定义bool truefalse但肯定不是一个好主意。这种能力被认为是过时的,将来会被移除。
  • 标量类型(算术类型和指针类型)分配给_Boolbool,如果量值等于00与之比较0,则为 ,否则结果为1:分配给 时_Bool x = 9; 9转换1x
  • _Bool是 1 个字节(8 位),通常程序员很想尝试使用其他位,但不推荐,因为给出的唯一保证是只有一位用于存储数据,而不像类型char有 8位可用。