我对左移操作员有疑问
int i = 1;
i <<= (sizeof (int) *8);
cout << i;
打印1。
如何以及为何是1?
答案 0 :(得分:14)
假设您的平台上sizeof(int)
为4。然后表达式变为:
i = i << 32;
标准说:
6.5.7-3
如果右操作数的值为负或大于或 等于提升左操作数的宽度,行为是 理解过程科幻奈德。
答案 1 :(得分:3)
作为cnicutar said,您的示例展示了未定义的行为。这意味着编译器可以自由地执行供应商认为合适的任何事情,包括making demons fly out your nose或者只是对手头的值做任何事情。
你可以做些什么来说服自己,左移位数会产生0
是这样的:
int i = 1;
i <<= (sizeof (int) *4);
i <<= (sizeof (int) *4);
cout << i;
答案 2 :(得分:2)
扩展previous answer ...
在x86平台上,您的代码将编译成如下所示:
; 32-bit ints:
mov cl, 32
shl dword ptr i, cl
CPU将变量i
中的dword移位cl
寄存器模32中包含的值。因此,32模32得到0.因此,转换并不会真正发生。根据C标准,这完全没问题。事实上,C标准在6.5.7-3中所说的是因为前面提到的CPU行为在当天很常见,并影响了标准。
答案 3 :(得分:1)
正如其他人已经提到的,根据C标准,转变的行为是不确定的。
也就是说,程序打印1.打印1的原因的低级说明如下:
在没有优化的情况下进行编译时,编译器(GCC,clang)会发出SHL
指令:
...
mov $32,%ecx
shll %cl,0x1c(%esp)
...
SHL
指令的英特尔文档说:
<强> SAL / SAR / SHL / SHR移强>
计数被屏蔽为5位(如果在64位模式下使用REX.W则为6位)。计数范围限制为0到31(如果使用64位模式和REX.W,则为63)。
将移位计数32(二进制00100000)屏蔽为5位,得到0(二进制00000000)。因此shll %cl,0x1c(%esp)
指令没有进行任何移位,并且i
的值保持不变。