考虑下面的代码:
// Simply loop over until 64 is hit.
unsigned long x = 0;
for (int i = 0; i <= 64; i++) {
if (i == 64) {
x = 1ul << i;
printf("x: %d\n", x);
}
}
我们知道unsigned long是64位宽,左移1位64位将变成1000...000(1后面有64个零),并且会被截断为0。然而,实际的打印输出给出:
x: 1
奇怪的是,如果我们这样做
printf("x: %d\n", (1ul << 64));
它会打印 0。
谁能解释为什么会发生这种情况?为什么在第一种情况下,程序错误地生成 1 而不是 0,但在第二种情况下却是正确的?
移动一个类型的宽度或多个原因未定义的行为 https://stackoverflow.com/a/4105123/1505939根据§6.5.7/3:
- 对每个操作数执行整数提升。方式
结果的 是提升后的左操作数的结果。如果值正确的操作数是负数或大于或等于宽度
提升的左操作数的行为未定义.
这样做的理由是,不同的 CPU 对超大的移位实现不同的行为,并且定义这种情况下的行为过于严格——许多移位需要生成额外的程序集。 (尽管也许它应该是实现定义的而不是未定义的)。
您的观察结果可以通过使用 Intel 系列 CPU 来解释,该 CPU 在硬件中对 64 位类型的移位宽度进行“mod 64”,因此在运行时1ul << 64
做了同样的事情1ul << 0
会;但在另一种情况下编译时编译器计算1ul << 64
使用算术规则。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)