当类型转换为 int 时,C/C++ bool 类型是不是总是保证为 0 或 1?

Posted

技术标签:

【中文标题】当类型转换为 int 时,C/C++ bool 类型是不是总是保证为 0 或 1?【英文标题】:Is C/C++ bool type always guaranteed to be 0 or 1 when typecast'ed to int?当类型转换为 int 时,C/C++ bool 类型是否总是保证为 0 或 1? 【发布时间】:2011-05-15 15:24:24 【问题描述】:

许多编译器似乎只在 bool 值中保留 0 或 1,但我不确定这是否总是有效:

int a = 2;
bool b = a;
int c = 3 + b; // 4 or 5?

【问题讨论】:

对于 C++ 部分,请参阅 [我可以为任何 C++ 编译器假设 (bool)true == (int)1 吗? ](***.com/questions/2725044/…)。对于 C,请参阅 [布尔是原生 C 类型吗? ](***.com/questions/1608318/is-bool-a-native-c-type)。 我对“布尔 表达式 是否总是保证评估为 0 或 1?”这个问题更感兴趣,答案是明确的 是的 相关:***.com/questions/5189072/c-bool-question 在较新的 C 版本中,有一个标准的 bool 类型,只有值 0 和 1,就像在 C++ 中一样。赋值将非零转换为 1。 请注意 bool cast 将确保 b 为 1。但您仍然可以使用 unions、memset 等技巧将 b 变为 2。 【参考方案1】:

是的:

在 C++ 中(第 4.5/4 节):

bool 类型的右值可以是 转换为 int 类型的右值, 假变成零和真 合而为一。

在 C 中,当一个值转换为 _Bool 时,它变为 0 或 1(第 6.3.1.2/1 节):

当任何标量值转换为 _Bool,如果值比较等于0,则结果为0;否则, 结果是 1。

转换为int 时,非常简单。 int 可以容纳 0 和 1,因此值没有变化(第 6.3.1.3 节)。

【讨论】:

请注意,对于 C,它取决于类型 _Bool。如果您改为使用typedef enum false, true bool;,则不会以这种方式工作。【参考方案2】:

嗯,不是总是...

const int n = 100;
bool b[n];
for (int i = 0; i < n; ++i)

    int x = b[i];
    if (x & ~1)
    
        std::cout << x << ' ';
    

我的系统上的输出:

28 255 34 148 92 192 119 46 165 192 119 232 26 195 119 44 255 34 96 157 192 119
8 47 78 192 119 41 78 192 119 8 250 64 2 194 205 146 124 192 73 64 4 255 34 56 2
55 34 224 255 34 148 92 192 119 80 40 190 119 255 255 255 255 41 78 192 119 66 7
8 192 119 192 73 64 240 255 34 25 74 64 192 73 64

标准 3.9.1 §6 中列出了这种明显奇怪的输出的原因:

bool 类型的值是 truefalse。以本国际标准描述为“未定义”的方式使用bool 值,例如检查未初始化的自动对象的值,可能会导致其表现得既不是true 也不是false

【讨论】:

@Sebastian:所以未初始化的变量已经定义了行为? @hha:注意int x = b[i]这一行,我真的希望这个随机的东西在这里被转换为0或1。不是吗? 不,不是真的,数组只是一块未初始化的内存,它可以包含任何东西,如果你做了 bool b[n] = 0 那就是另一回事了。但是,您对标准的引用提供了丰富的信息,因此 + 1 用于指出异常 @Sebastian: 试图访问一个未初始化的变量 is UB。 @FredOverflow:是吗?没想到什么,毕竟是UB。你真的认为每次访问布尔值时都应该有一个转换步骤吗?除了truefalse 之外,没有任何定义的方法可以将任何内容存储到布尔变量中。 @Sebastian:你完全错了。如果您访问未初始化变量的值,则允许发生其他事情,包括终止程序或system("rm -rf /"); 【参考方案3】:

是 C/C++.......

没有名为 C/C++ 的语言。

当类型转换为 int 时,bool 类型始终保证为 0 或 1?

在 C++ 中是的,因为第 $4.5/4 节说

bool 类型的右值可以转换为 int 类型的右值,false 变为 0,true 变为 1。

.

int c = 3 + b; // 4 还是 5?

c 的值为 4

【讨论】:

除了在 C 中,C 甚至没有 bool 类型 :) @hhafez :在 C 中,直到 C99,没有 bool 数据类型。请举起你的反对票。 C99 在标头&lt;stdbool.h&gt; 中定义了一个新类型_Bool 和一个typedef bool。如果你不使用#include &lt;stdbool.h&gt;,你的程序就不能使用bool,但是它们可以使用_Bool -1 指出没有称为 C/C++ 的语言。这句话在迂腐上是正确的,但故意没有帮助。原发帖人并没有提到 C/SQL 之类的东西。如果您了解 C++ 但不了解 C 标准,请直说。 @thb 我不同意这句话没有帮助。 C++ 是具有更多特性的 C 的想法非常普遍。两种语言的标准在很多方面存在差异,这是一个重要的考虑因素。【参考方案4】:

当您脱离安全船时的另一个例子:

  bool b = false;
  *(reinterpret_cast<char*>(&b)) = 0xFF;
  int from_bool = b;
  cout << from_bool << " is " << (b ? "true" : "false");

输出(g++ (GCC) 4.4.7):

  255 is true

待添加到FredOverflow's example。

【讨论】:

【参考方案5】:

C pre C99(如 C90)中没有 bool 类型,但 C99/C++ 中的 bool 类型始终保证为 0 或 1。

在 C 中,无论是否定义了布尔类型,所有布尔运算都保证返回 0 或 1。

所以a &amp;&amp; b!aa || b 在C 或C++ 中将始终返回0 或1,而不管ab 的类型如何。

【讨论】:

C 确实有bool。从技术上讲,类型是 _Boolbool 是一个宏,但这通常无关紧要,除非您使用的是冲突库。 @hhafez:C 中的标准化布尔类型 (_Bool) 比 C# 等语言更早。毕竟没有太多的 C 经验? C 和 C# 有什么关系我不明白你的评论【参考方案6】:

如果填充位不包含该类型的预期值,则具有填充位的类型可能会表现得很奇怪。大多数 C89 实现不使用任何整数类型的填充位,但 C99 要求实现定义这样的类型:_Bool。当所有位都为零时读取_Bool 将产生零。将任何非零值写入_Bool 会将其位设置为某种模式,读取时将产生 1。写入零会将位设置为一种模式(可能是也可能不是全位为零),读取时将产生 0。

除非在实现的文档中另有说明,否则不能通过将零或非零值存储到_Bool 来产生除全位零以外的任何位模式都是陷阱表示;标准没有说明如果尝试读取这样的值会发生什么。给定,例如

union boolChar  _Bool b; unsigned char c;  bc;

将零存储到bc.c 并读取bc.b 将产生零。将零或一存储到bc.b 将设置bc.c 的值,如果写入,将导致bc.b 保持零或一。将任何其他值存储到 bc.c 并读取 bc.b 将产生未定义的行为。

【讨论】:

我同意_Bool 的表示需要有填充位,但我没有看到断言“除了所有位为零之外的任何位模式都不能已通过将 0 或 1 存储到 _Bool 来产生是一个陷阱表示”。 _Bool 或任何其他带有填充位的整数类型明确可能提供陷阱表示,但标准不要求或任何其他特定的填充解释,也不要求存在给定类型支持的每个值的唯一有效表示。 @JohnBollinger:该标准对实现如何处理不需要分配含义的任何位模式没有任何要求。实现可以记录他们将如何处理对此类模式的读取,但他们也可以记录从标准的角度来看调用未定义行为的任​​何其他操作。 这或多或少是我的观点,@supercat。标准(间接)要求_Bool 类型的表示具有填充位这一事实并不意味着该类型必须提供任何陷阱表示,也不意味着任何满足您提出的标准的特定位模式都需要是陷阱表示。该标准不将有效表示限制为可以作为赋值表达式的副作用存储的那些。 @JohnBollinger:从标准的角度来看,如果不是“不需要表示对象类型值的对象表示”,那么什么是陷阱表示,即实现的位模式是否必须附加含义?允许实现将含义附加到标准要求之外的位模式,但实现恰好记录位模式的含义这一事实不会阻止它成为“不需要指定对象值的对象表示”类型”。 您对 trap 表示 的定义的解释超出了我的预期或保证范围。考虑标准的规定,对于符号值整数,具有符号位 1 和所有其他位 0 的表示是否是陷阱表示是实现定义的。就标准而言,该模式不必表示值,但也不一定是陷阱表示。我认为“不需要代表一个值”的措辞有点矫揉造作,但应该从实现的角度来解释。

以上是关于当类型转换为 int 时,C/C++ bool 类型是不是总是保证为 0 或 1?的主要内容,如果未能解决你的问题,请参考以下文章

在 swift assert(0) 中无法将 Int 类型的值转换为预期的参数类型 Bool

隐式转换和显式转换

C++将派生类赋值给基类(向上转型)

C/C++ 高效位数组

怎么把一个string类型转换为bool类型

windows编程问题 错误提示“int无法隐式转换为bool”