为什么是0x7FFFFFFFull | (1 <&lt; 31)在C ++中返回0xFFFFFFFFFFFFFFFF?

时间:2015-06-18 01:46:31

标签: c++ bit-manipulation bitwise-operators bit-shift

当我这样做(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

2 个答案:

答案 0 :(得分:7)

首先,您的代码不会在标题/问题中执行您所说的内容;我已经编辑了标题。

问题是1 << 31。如果你有32位int(显然你这样做,根据结果判断),这会导致算术溢出。在C ++ 14中,这是实现定义的行为;在C ++ 14之前,它会导致未定义的行为。 Reference

通常,实现定义的行为是生成符号位设置的int,其他位未设置。在2的补码中,该值为INT_MIN。然后,您在unsigned long longint之间执行算术运算。这定义为: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,然后将它扩展为'| ='

的long