-2

你能告诉我为什么下面的代码由于左移a带有负值的无符号数而给出负结果吗?

    int main(void)
     {
          unsigned int a=1;
          printf("%d",a<<-1);   

     }

输出 -2147483648。

4

2 回答 2

5

这篇文章

如果右操作数的值为负数或大于或等于提升的左操作数的宽度,则行为未定义。

所以你正在做的是未定义的行为。如果您想要可预测的行为,请不要移动负数的位数。

于 2013-05-07T07:18:11.480 回答
1

除了这是未定义的行为这一事实之外,我们还可以尝试考虑在您的情况下会发生什么。但要注意,这也取决于编译器和底层机器。在这个答案中,我在 x86 机器上使用 VC++ 2010。

看一下代码

#include "stdafx.h"

int main(int argc, _TCHAR* argv[])
{
    unsigned int a  = 1;
    printf("%d",a<<-1);   

    a  = 1;
    printf("%d",a<<31);   
}

两种转变都给出了相同的答案。要了解发生了什么,我们需要看一下这种情况下的反汇编。

010E1A4E  mov         dword ptr [a],1  
010E1A55  mov         eax,dword ptr [a]  
010E1A58  shl         eax,0FFh  
...

010E1A73  mov         dword ptr [a],1  
010E1A7A  mov         eax,dword ptr [a]  
010E1A7D  shl         eax,1Fh  
...

负移编译为shl eax, 0ffh. 对于 x86,移位指令的位移只能是 8 位,这就是编译器在这里使用(-1 & 0xff) = 0xff. 但是指令本身会用0x1f. 因此,两个班次具有相同的结果。执行移位后,结果将是与 -2147483648 相同的0x80000000整数(请注意您%d在 中使用)。printf

于 2013-05-07T07:42:11.670 回答