这有点让我发疯。
int a = 0xffffffff;
int b = 32;
cout << (a << b) << "\n";
cout << (0xffffffff << 32) << "\n";
我的输出是
-1
0
为什么我没有
0
0
答案 0 :(得分:10)
当您将值移位不小于其大小的位数时(例如,对于32位整数为32位或更多位),会发生未定义的行为。您刚刚遇到了一个未定义行为的示例。
答案 1 :(得分:10)
简短的回答是,由于您使用的是32位int
的实现,因此语言标准称32位移位是未定义的行为。 C标准(第6.5.7节)和C ++标准(第5.8节)都说
如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。
但是如果你想知道为什么:
许多计算机都有一条指令可以移动寄存器中的值,但硬件只处理实际需要的移位值。例如,当移位32位字时,仅需要5位来表示0 ... 31的移位值,因此硬件可能忽略更高阶位,并且在* 86机器上(8086除外)。因此,编译器实现可以只使用该指令而不生成额外的代码来检查移位值是否太大,C标准的作者(其中许多代表编译器供应商)裁定更大量的移位结果是未定义的。 / p>
您的第一个班次是在运行时执行的,它遇到了这种情况......您的机器只考虑b的低位5位,它们是0,因此不会发生转换。第二次转换是在编译时完成的,编译器以不同的方式计算值,实际上是32位移位。
如果您想要移动的数量可能大于您正在移动的事物中的位数,则需要自己检查值的范围。一种可行的方法是
#define LEFT_SHIFT(a, b) ((b) >= CHAR_BIT * sizeof(a)? 0 : (a) << (b))
答案 2 :(得分:0)
C ++标准说:: 如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。 由于海湾合作委员会没有选择以负数或超出该类型宽度的数量来处理轮班,也可能陷入其中;他们总是被视为未定义。 所以没有定义行为。