我一直在进行一些关于位操作的愚蠢测试,然后发现了这个问题。我执行了以下代码:
int main(){
unsigned int i;
for (i=1; i<34; i++)
{
unsigned long temp = i;
unsigned long mul = 1;
unsigned long val;
unsigned long one = 1;
// Way 1
while (temp--)
mul = mul << one;
// Way 2
val = (one<<i);
printf(" \n 1<<%i \n mul: 0x%X , val: 0x%X\n",i, mul, val);
}
}
当 i>31 时,我知道会产生溢出。我认为代码的两个部分(way1 和 way2)应该输出相同的结果。但是最终结果是这样的:
/* ... correct results from i=1 to i=31 ... */
1<<30
mul: 0x40000000 , val: 0x40000000
1<<31
mul: 0x80000000 , val: 0x80000000
1<<32
mul: **0x0** , val: **0x1**
1<<33
mul: **0x0** , val: **0x2**
为什么两种指令都是左移,程序会产生不同的输出?似乎way2部分执行了一个圆形的移位,但我不知道为什么,我真的认为“mul”总是得到正确的值。
我在Intel 32位机器上编译,gcc版本为4.4.7。
one
是一个变量,而不是常量。 - Mr Listerprintf
也会引发未定义行为。 - too honest for this site