【问题标题】:Why does bool and not bool both return true in this case? [duplicate]为什么在这种情况下 bool 和 not bool 都返回 true? [复制]
【发布时间】:2014-04-24 12:03:14
【问题描述】:

这是我的代码:

#include <cstring>
#include <iostream>
int main() {
    bool a;
    memset(&a, 0x03, sizeof(bool));
    if (a) {
        std::cout << "a is true!" << std::endl;
    }
    if (!a) {
        std::cout << "!a is true!" << std::endl;
    }
}

它输出:

a is true!
!a is true!

似乎bool 上的! 运算符只反转最后一位,但每个不等于0 的值都被视为true。这导致了所示的行为,这在逻辑上是错误的。这是实现中的错误,还是规范允许这样做?请注意,memset 可以省略,并且行为可能是相同的,因为a 包含内存垃圾。

我使用的是 gcc 4.4.5,其他编译器可能会采用不同的方式。

【问题讨论】:

  • 哇,但你为什么还要...
  • 看来这个问题至少在 GCC 4.6 Demo 中得到了修复。
  • LLVM 5.1 (clang-503.0.38) 也没有出现这个问题。
  • 允许编译器假定bool 值是truefalse,因为bool 只能具有这些值。 (非零整数值转换为 - 不视为 - true 无关紧要,因为此代码中没有进行任何转换。)
  • @flyx:未定义的行为.. 无人登陆。一切顺利

标签: c++ boolean


【解决方案1】:

标准(3.9.1/6 Fundamental types)说:

bool 类型的值为真或假。

....

以本国际标准描述为“未定义”的方式使用布尔值,例如通过检查 未初始化的自动对象,可能会导致其表现得既不真也不假。

您的程序对memset 的使用会导致未定义的行为。其结果可能是该值既不是真也不是假。

【讨论】:

  • 我会添加 3.9.1/1 “对于无符号字符类型,值表示的所有可能的位模式都表示数字。这些要求不适用于其他类型。”
  • 但是如果它既不是真也不是假,那么两个if语句都不应该被执行?!似乎 OPs 代码确实导致它表现得既是真又是假:-/
  • @Bergi 根据定义,如果它同时表现出两者,那么它不是
【解决方案2】:

这不是“逻辑错误”,而是未定义的行为。 bool 应该只包含两个值之一,truefalse。为其赋值将导致转换为这些值之一。通过在其内存顶部写入任意字节值(或者,正如您提到的,将其保持未初始化)来破坏类型安全性不会,因此您最终可能会得到一个既不是 true 也不是 false 的值。

【讨论】:

  • 是NULL还是什么都没有?
  • @Ben 是 NULL 还是什么都没有?价值?两者都不。在 OP 的示例中,值为 3,如您所见,它既不是真也不是假。现在是 3。
  • @MattMcNabb 这将取决于实现。布尔值在转换为 int 时保证为01。但是,内部表示可能不同。据我们所知,bool 可以存储为 32 位浮点数,然后 true 的表示形式将是 00 00 80 3F
  • @EvgeniSergeev:我不知道你在说什么。 bool 有两个值,两者都不是0x03;使用memsetbool 重新解释为一个或多个字节,并用非bool 值覆盖它,会给出未定义的行为。肯定不是“零代表错误,其他任何代表正确”的情况;只有true 表示真实。您所说的“约定”是 C 古代方言的一种解决方法,它缺乏布尔类型;不适用于 C++。
  • @EvgeniSergeev:哦,我明白了,您指的是到bool 的类型转换,而不是bool 的值。但是这段代码专门抑制了类型转换,通过使用memset 直接写入底层内存,而不知道可能存在任何类型。如果您故意规避语言对它的保护,那么(在我看来)获得未定义的行为是非常合理的。如果您想要类型转换,请使用赋值(用于单个对象)或std::fill/copy(用于序列),并在您确实需要危险地处理原始内存时留下memset/memcpy
【解决方案3】:

在内部,它可能会使用按位非(~ 运算符)来反转它,这在 bool 为零或全为 1 时会起作用:

 a = 00000000 (false)
!a = 11111111 (true)

但是,如果您将其设置为三个:

 a = 00000011 (true)
!a = 11111100 (also true)

【讨论】:

  • 到目前为止,在我见过的所有编译器上,生成的程序集都使用testb(或等效的)指令来处理 OP 代码,并且在内部将其转换为一个比较和 if/else。如果我们只使用!a 版本,它会变成一个xor 和一个testb...这个调用可以在gcc explorer 上玩。
  • 这是编译器的实现细节。在标准中的哪里可以找到这些信息?
  • 我真的怀疑任何实现都将true 存储为所有的。鉴于bool 可以如何转换为具有01 值的int,它更有可能也是以这种方式存储的。
猜你喜欢
  • 2014-09-12
  • 2019-03-07
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-31
  • 1970-01-01
相关资源
最近更新 更多