通过左移,可以将数字设置为零

时间:2012-02-24 10:28:18

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

我对左移操作员有疑问

int i = 1;
i <<= (sizeof (int) *8);
cout << i;

打印1。

  1. 我已初始化为1。
  2. 在将位移动到整数的大小时,它将LSB填充为0并且当1超过整数的限制时,我期望输出为0.
  3. 如何以及为何是1?

4 个答案:

答案 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的值保持不变。