【问题标题】:Using boolean values in C在 C 中使用布尔值
【发布时间】:2010-12-27 15:37:37
【问题描述】:

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

【问题讨论】:

标签: c boolean


【解决方案1】:

任何非零值在布尔运算中都被评估为真,所以你可以

#define TRUE 1
#define FALSE 0

并使用常量。

【讨论】:

  • 但要小心使用它们:因为真实的结果可能是任何非零值,测试 if(t==TRUE){...} 和 if(t),它们在其他语言,在 C 中是不等价的。
  • 你是对的,但在具有 bool 类型的 C++ 中也是如此,对吧?在调试过程中,我看到布尔变量的值为 5837834939...
  • 在 C++ 中,if(t == true) 测试等于 if(t) 测试,因为 C++ 进行了一些转换(所有非 0 或空指针值都转换为 true)
  • 你应该假设一个布尔真值是非零的。所以像 if( b ) 这样的代码是安全的,而 if( b == TRUE) 则不是;后者是不好的做法(而且毫无意义)。
【解决方案2】:

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

另见Boolean data type, section C, C++, Objective-C, AWK

【讨论】:

  • 它也适用于逻辑运算符(&& 和 ||)。
【解决方案3】:

从好到坏:

选项 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!

【讨论】:

  • 您能否详细说明为什么它们是最好到最差的选择?
  • @endolith 编译器选择的对齐、优化和存储&lt;stdbool.h&gt; bool 的方式可能比使用int 更适合布尔值的预期目的(即编译器可以选择以不同于int 的方式实现bool)。如果幸运的话,它还可能导致在编译时进行更严格的类型检查。
  • 为什么将int 用于bool?那很浪费。使用unsigned char。或者使用C的内置_Bool
  • @NoBody 使用较小的类型可以节省内存,但可能不会使其更快。通常,使用处理器的本机字长而不是较小的字长会更快,因为它可能需要编译器进行位移以正确对齐它
  • 选项 2-4 的行为与 &lt;stdbool.h&gt; 不同。例如,它们不满足(bool)(13 &amp; 8) == true。对于选项 2-4,您必须改写 !!(13 &amp; 8) == true。这一直出现在位域测试中……想想一个返回 (13 &amp; 8) 且返回类型为 bool 的宏。
【解决方案4】:

您可以使用 char 或其他小数字容器。

伪代码

#define TRUE  1
#define FALSE 0

char bValue = TRUE;

【讨论】:

  • 同样在 C 中它通常是一个 int,它可能会导致其他使用 int 的代码丢失精度警告。
  • 除非您手动优化空间,否则最好使用硬件的正常字长(例如:通常是int),因为在某些架构上,您会因为拥有解压/屏蔽对这些变量的检查。
【解决方案5】:

是这样的:

#define TRUE 1
#define FALSE 0

【讨论】:

  • 我会选择 #define TRUE !FALSE 之类的东西
【解决方案6】:
typedef enum {
    false = 0,
    true
} t_bool;

【讨论】:

  • 2 到 MAX_INT 也应该评估为真
  • @technosaurus 采用这种方法并不能保证 !false == true 因为 !false 可以是任何非零数字。一个简单的解决方法是将 true 显式分配给 !false。
  • @Andrew 这不是真的。 !0 = 1 按 C 标准,!a = 0 表示 a 的任何非零值。问题是任何非零都被认为是真实的。因此,如果ab 都是“真”,则不一定是`a == b`。
【解决方案7】:

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

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

【讨论】:

  • 10 年的标准,但不是 10 年的编译器!除了允许 // cmets 之外,MSVC++ 的 C 编译根本不支持 C99,而且不太可能这样做。 _Bool 在 C99 中也被定义为内置类型,而 bool 是 标头中的 typedef。
  • @Clifford 自您发表评论 4 年后...一切都没有改变。 MSVC 是一个 C++ 编译器,我相信 MS 说过他们并不真正热衷于支持所有新的 C 功能(C99 和 C11)。但是我不能以 MSVC 不支持新的 C 功能为理由(尤其是当您反对 10 年 的答案时)。 10 年在编程世界中确实是一段很长的时间。如果供应商打算支持它,任何体面的编译器都应该在不到 10 年的时间内支持它。
  • @KingsIndian:我不知道你为什么把你的评论发给我,甚至觉得有必要发表评论。我只是陈述撰写本文时的情况。我不支持这种情况,只是指出“答案”可能不适用于所有情况。
  • @Clifford:严格来说,标准要求bool 是扩展为_Bool 的宏。区别很重要,因为您可以#undef 宏(这是允许的,至少作为过渡措施),但您不能untypedef 类型定义。不过,它不会改变您第一条评论的主旨。
  • VS2015 及更高版本(可能更早,在一定程度上)在 C 编译下对 bool&lt;stdbool.h&gt; 没有问题。它解析为_Bool
【解决方案8】:

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

#include <stdbool.h>
int main()
{
  bool b = false;
  b = true;
}

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

【讨论】:

  • 它们不是“内置”的,它们只是在包含文件stdbool.h 中进行类型定义,因此您在包含文件中包含typedef enum {false, true} bool;
  • @JamesStevens 这是不对的。有一个名为_Bool 的内置类型。它不是枚举。 booltruefalse 是在 &lt;stdbool.h&gt; 中定义的宏,它们分别扩展为 _Bool10。见en.cppreference.com/w/c/types/boolean
【解决方案9】:

如果条件表达式不为零,则认为它们为真,但 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 比较,无论如何都会触发警告。

【讨论】:

    【解决方案10】:

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

    我已经足够大了,我只使用普通的ints 作为我的布尔类型,没有任何类型定义或特殊定义或真/假值的枚举。如果您按照我下面的建议从不与布尔常量进行比较,那么您只需要使用 0/1 来初始化标志。然而,在当今时代,这种做法可能被认为过于反动。在这种情况下,绝对应该使用&lt;stdbool.h&gt;,因为它至少具有标准化的好处。

    无论调用什么布尔常量,仅将它们用于初始化。永远不要写类似

    的东西
    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 不工作吗?
    • @Kenji 你说的是真的,虽然我相信使用一个值以外的值作为真值几乎总是一个坏主意。因此,在您的示例中,假设 ab 从零开始计数,我建议改为 a &gt; 0 == b &gt; 0。如果你坚持要利用任意非零值的真实性,!!var 会产生与var 等价的布尔值 0/1,所以你可以写成!!a == !!b,尽管很多读者会觉得它令人困惑。
    • !a == !b 也足以测试相等性,非零变为零,零变为一。
    • @rpattiso 当然,你说的很对,但我想我会将!!a 读作“将非布尔a 转换为其等效的真值”,而我会读到!a作为“逻辑反转布尔变量a”。特别是,我会寻找一些需要逻辑反转的特定原因。
    【解决方案11】:

    这是我使用的版本:

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

    因为 false 只有一个值,但逻辑 true 可以有多个值,但技术将 true 设置为编译器将用于 false 的反义词。

    这可以解决有人编码的问题,这会归结为:

    if (true == !false)
    

    我想我们都同意这不是一个好的做法,但是一次性执行“true = !false”的成本我们消除了这个问题。

    [编辑] 最后我使用了:

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

    避免与定义truefalse 的其他方案发生名称冲突。但概念保持不变。

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

    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 个字节。

    【讨论】:

    • 使用枚举的另一个好处是 IDE 集成 - truefalsebool 在大多数 IDE 中突出显示,因为它们是枚举值和 typedef,而不是 #defines , 很少会突出显示语法。
    • 好奇:忽略它是否真的有效,C(99+) 允许一个枚举引用 same enumeration 中的先前值是否有效?
    • “因为 false 只有一个值,但逻辑 true 可以有多个值,但技术将 true 设置为编译器将用于 false 的反面。”否定运算符! 只能返回值01,因此true = !false 将始终分配值1。这种方法不会比typedef enum { false, true } bool; 提供任何额外的安全性。
    • 最早我发现是来自C90(6.3.3.3一元算术运算符):“如果其操作数的值比较不等于0,则逻辑否定运算符的结果为0。1如果其操作数的值比较等于 0。结果的类型为 int。表达式 !E 等价于 (O==E)。" 这应该涵盖任何声称支持标准 C 的编译器。编译器在与可观察行为无关的情况下(如if(!value))当然可以合法地忽略此规则,但该例外不适用于这种特定情况。
    • 那些自定义的有 4 个字节长,使用它们是不切实际的。有什么方法可以用 CHAR 类型实现吗?
    【解决方案12】:

    您可以简单地使用#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);
    

    等等

    【讨论】:

    • NOT 宏应由 arg 和整个表达式的括号保护:#define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE)。但是,最好测试一下是否为假(即使arg 是 23 而不是 0 或 1,它也会给出正确答案:#define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)。但是整个表达式当然可以简化为 #define NOT(arg) (!(arg)),这产生相同的结果。
    【解决方案13】:

    首先要做的事情。 C,即 ISO/IEC 9899 的布尔类型已有 19 年。这比访问 this question 时的 expected 业余/学术/专业部分的 C 编程职业生涯长得多。我的确实超过了大约 1-2 年。这意味着在普通读者完全了解 C 的过程中,C 实际上拥有布尔数据类型

    对于数据类型#include &lt;stdbool.h&gt;,并使用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 为零,否则trueC11 6.3.1.2p1

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

    脚注

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

    使用typedefdouble 将被强制转换为int - 如果双精度值不在int 的范围内,则行为未定义强>。

    如果truefalseenum 中声明,自然同样适用。

    更危险的是声明

    typedef enum bool {
        false, true
    } bool;
    

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

    因此iff由于某些莫名其妙的原因,您不能使用 C99,对于布尔变量,您应该使用:

    • 键入int 和值01 原样;并小心地将任何其他值的域转换为双重否定!!
    • 或者如果你坚持你不记得 0 是假的和非零的真值,至少使用 大写 这样他们就不会混淆C99 概念:BOOLTRUEFALSE

    【讨论】:

    • C 标准的哪一部分将限制枚举类型的对象保留其中明确列出的值?如果枚举常量的最大值小于 UCHAR_MAX 或 USHRT_MAX,则实现可以使用小于 intunsigned int 的类型来保存枚举,但我不知道标准中会导致枚举行为作为整数类型以外的任何东西。
    【解决方案14】:

    如果您被允许使用 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 不是unsigned int,而是无符号整数类型组的一部分。它足够大,可以容纳 01 的值。
    • 不要,但是可以,您可以重新定义 bool truefalse 但肯定不是一个好主意。此功能已过时,将来会被移除。
    • 如果 scalar 值等于 0 或与0 将是0,否则结果是1_Bool x = 9; 9 分配给1 时转换为1
    • _Bool 是 1 字节(8 位),通常程序员很想尝试使用其他位,但不推荐使用,因为唯一保证的是只使用一位来存储数据,而不是像 type char 有 8 位可用。

    【讨论】:

      【解决方案15】:

      您可以使用 _Bool,但返回值必须是整数(1 表示真,0 表示假)。 但是,建议在 C++ 中包含和使用 bool,如 this reply 来自daniweb forum,以及this answer,来自另一个stackoverflow 问题:

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

      【讨论】:

        【解决方案16】:

        如果您使用的是 C99,那么您可以使用 _Bool 类型。不需要#includes。不过,您确实需要将其视为整数,其中 1true0false

        然后您可以定义TRUEFALSE

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

        【讨论】:

        • 或者您可以#include &lt;stdbool.h&gt; 并按照标准要求使用booltruefalse
        【解决方案17】:

        现在C99 支持布尔类型,但您需要#include &lt;stdbool.h&gt;

        例子:

        #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
        

        【讨论】:

          【解决方案18】:

          这是我用的:

          enum {false, true};
          typedef _Bool bool;
          

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

          【讨论】:

            猜你喜欢
            • 2017-08-14
            • 2023-03-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-20
            • 2021-12-27
            • 1970-01-01
            相关资源
            最近更新 更多