当我这样做(0x7fffffff | 0x8000000)时,我得到0xffffffffffffffff而不是预期的0xffffffff。我错过了什么?
一些示例代码和输出来说明我的问题。
代码:
#include <iostream>
using namespace std;
int main()
{
unsigned long long val = 0;
for (int i = 0; i < 64; i++) {
val |= 0x1 << i;
cout << i << ": " << std::hex << val << std::dec << endl;
}
return 0;
}
输出:
0: 1 1: 3 2: 7 3: f 4: 1f 5: 3f 6: 7f 7: ff 8: 1ff 9: 3ff 10: 7ff 11: fff 12: 1fff 13: 3fff 14: 7fff 15: ffff 16: 1ffff 17: 3ffff 18: 7ffff 19: fffff 20: 1fffff 21: 3fffff 22: 7fffff 23: ffffff 24: 1ffffff 25: 3ffffff 26: 7ffffff 27: fffffff 28: 1fffffff 29: 3fffffff 30: 7fffffff 31: ffffffffffffffff 32: ffffffffffffffff 33: ffffffffffffffff 34: ffffffffffffffff 35: ffffffffffffffff 36: ffffffffffffffff 37: ffffffffffffffff 38: ffffffffffffffff 39: ffffffffffffffff 40: ffffffffffffffff 41: ffffffffffffffff 42: ffffffffffffffff 43: ffffffffffffffff 44: ffffffffffffffff 45: ffffffffffffffff 46: ffffffffffffffff 47: ffffffffffffffff 48: ffffffffffffffff 49: ffffffffffffffff 50: ffffffffffffffff 51: ffffffffffffffff 52: ffffffffffffffff 53: ffffffffffffffff 54: ffffffffffffffff 55: ffffffffffffffff 56: ffffffffffffffff 57: ffffffffffffffff 58: ffffffffffffffff 59: ffffffffffffffff 60: ffffffffffffffff 61: ffffffffffffffff 62: ffffffffffffffff 63: ffffffffffffffff
答案 0 :(得分:7)
首先,您的代码不会在标题/问题中执行您所说的内容;我已经编辑了标题。
问题是1 << 31
。如果你有32位int
(显然你这样做,根据结果判断),这会导致算术溢出。在C ++ 14中,这是实现定义的行为;在C ++ 14之前,它会导致未定义的行为。 Reference
通常,实现定义的行为是生成符号位设置的int,其他位未设置。在2的补码中,该值为INT_MIN
。然后,您在unsigned long long
和int
之间执行算术运算。这定义为:int
转换为unsigned long long
。
将有符号整数转换为无符号是通过将其包围(模运算)模ULLONG_MAX+1
来完成的。因此(unsigned long long)INT_MIN
的结果是一个非常大的正数,实际上是0xFFFFFFFF80000000
。 (要进行检查,请向其添加0x80000000
以获取0
)。
所以你实际上正在做0x7FFFFFFF | 0xFFFFFFFF80000000
,它给出了观察到的结果。
稍后它会变得更糟:1 << 32
和更大会导致由于移动类型的整个宽度而导致的未定义行为。
要解决此问题,请将代码中的0x1
更改为1ull
。您将转移unsigned long long
,而不是int
。
答案 1 :(得分:1)
因为符号扩展val
是一个无符号长long。但是val不是你正在改变的。你正在转移0x1,一个int,然后将它扩展为'| ='