该程序输出的每一行等于2 ^ i
- 2,除了最后一行,等于2 ^ 64 - 1.为什么会这样?
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
int main(void) {
unsigned long long ONE = 1;
unsigned long long i;
for (i = 1; i <= 64; i++) {
printf("%"PRIu64"\n", (ONE << i) - 2);
}
return EXIT_SUCCESS;
}
输出:
0
2
6
14
30
62
126
254
510
1022
2046
...
4611686018427387902
9223372036854775806
18446744073709551615
答案 0 :(得分:5)
您将64位移到64位类型(计算机上为unsigned long long
),这是未定义的行为。
BTW,unsigned long long ONE = 1;
编码风格不好,您只需使用1ULL
。
C11§6.5.7按位移位运算符
对每个操作数执行整数提升。结果的类型是 升级的左操作数。 如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。
答案 1 :(得分:4)
假设ULL
类型的宽度为64位,则表示您处于未定义的行为区域。根据{{1}}:
如果右操作数的值为负或大于或等于提升的左操作数的宽度,,则行为未定义。
可能发生的是移位值以64为模减少,C11 6.5.7 Bitwise shift operators
为零。因此,它只是评估包裹到64 % 64
的{{1}}。但是,老实说,由于UB没有施加任何真正的限制,它可能只是从空中榨取结果: - )
答案 2 :(得分:1)
1ULL&lt;&lt; 64未定义,而定义移位较少。
有关语言标准的详细信息,请参阅Is Shifting more than 32 bits of a uint64_t integer on an x86 machine Undefined Behavior?。
答案 3 :(得分:0)
您达到了64位(长很长)的位限制。显然,左移2 ^ 63会导致翻转,导致2 ^ 0 = 1。
1 - 2 = -1当被视为无符号时(假设为long long)为2 ^ 64-1。
这个结果很有意思,因为左移的非翻转实现会导致0而不是1,这在减法后会产生2 ^ 64-2。