在 bool 中设置额外的位使得它同时为 true 和 false

共2个回答, 标签: c++ boolean undefined-behavior evaluation abi

如果我得到一个布尔变量,并将其第二位设置为 1,然后变量同时计算为 true 和 false。使用-g 选项 (gcc-v6.3.0/Linux/RHEL6.0-2016-x86 _ 64/bin/g-g main.cpp-o mytest _ d) 编译以下代码并运行可执行文件。你得到下面的。

如何不能同时等于真与假?

值位
--- ---
T: 1 0001
位更改后
T: 3 0011
T 是真的
T 是假的

当你用不同的语言调用一个函数时,这种情况可能会发生,其中 true 和 false 定义不同于 C。对于 fortran 来说,如果任何位不是 0,则值为 true,如果所有位都是 0,则值为 false。

# 包括
# 包括

使用命名空间 std;

Void set _ bit _ to _ 1 (void * val) {
Char * x = static_ cast (val);

对于 (int i = 0; i <2; i) {
* X | = (1UL <<i);
}
}

Int main (int argc,char * argv [))
{

Bool T = 3;

Cout <<"值位" <(T) <bit_T = bitset <4> (T);
Cout <<位更改后 <<
第1个答案

在 C 中,a 的位表示 (甚至大小)布尔定义了实现; 通常它是作为Char-取 1 或 0 作为可能值的大小类型。

如果您将其值设置为与允许的值不同的值 (在这种特定情况下,通过别名布尔通过一个Char你违反了语言的规则,所以任何事情都可能发生。特别是,标准中明确规定了一个 “破碎”布尔可能表现为两者假的(或者都不也不假的) 同时:

使用一个布尔以这种国际标准描述为 “未定义” 的方式来表示值,例如通过检查未初始化的自动对象的值,可能会导致它的行为看起来既不也不假的

(C 11 、【基本】、注 47)


在这种特殊情况下你可以看到它是如何在这种奇怪的情况下结束的: 第一如果编译为

字节 PTR [rbp-33]
测试 al,al
Je。L22

哪个负载TEax(扩展名为零),如果全部为零,则跳过打印; 如果不是,则跳过下一个

字节 PTR [rbp-33]
异 eax,月
测试 al,al
Je。L23

测试的如果 (T = = false)被转化为如果 (T ^ 1),只是低一点翻转。这对于一个有效的布尔,但是对于你的 “破” 一个,它不会切它。

请注意,这个奇怪的序列只在低优化级别生成; 在更高的级别,这通常会归结为零/非零检查,像你这样的序列可能会变成单个测试/条件分支。无论如何,在其他情况下,你会得到奇怪的行为,例如当求和时布尔其他整数的值:

Int foo (bool b,int i) {
返回 i b;
}

成为

Foo (int,int):
Movzx edi,双列直插
Lea eax,[rdi rsi]
Ret

哪里迪尔0/1 是 “值得信赖的”。


如果你的程序都是 C,那么解决方法很简单:布尔这样,避免混淆它们的位表示,一切都会顺利; 特别是,即使你从整数赋值给布尔编译器将发出必要的代码,以确保生成的值是有效的布尔所以你的布尔 T = 月确实是安全的T会以一个在它的内脏。

相反,如果你需要与用其他语言编写的代码进行互操作,这些代码可能对布尔就是,避免布尔对于 “边界” 代码,并将其作为适当大小的整数封送。它将在条件句 & co 中工作一样好。

第2个答案

当你违反了语言和编译器的约定时,会发生这种情况。

你可能在某个地方听说过 “零是假的” 和 “非零是真的”。当您坚持语言的参数时,静态转换Int布尔反之亦然。

当你开始摆弄位表示时,它不成立。在这种情况下,你违反了你的合同,进入了 (至少) 实现定义行为的领域。

不要那样做。

这不是由你来决定的布尔存储在内存中。这取决于编译器。如果你想换一个布尔的值,要么分配/假的,或者指定一个整数,并使用 C 提供的正确转换机制。

相关问题

此类型和函数是否有现有名称? 将位与布尔值进行比较 在 bool 中设置额外的位使得它同时为 true 和 false 通过 const ref 未定义行为捕获新构造的对象 通过指针算术访问结构数据成员 Std::min(0.0、1.0) 和 std::max(0.0、1.0) 是否会产生未定义的行为? JLS 中 f1 () f2 () * f3 () 表达式和运算符优先级的执行顺序 然后用子程序的输出替换 Perl6 搜索 为什么32位和64位系统上的 "对齐方式" 相同? 为什么 T * 可以通过注册,但 unique_ptr<T>不能?