为什么这两种方法将变量设置为全1会产生不同的结果?

时间:2014-02-03 10:57:10

标签: c

我最近发现在C中将变量设置为全1的两种方法之间存在差异。 这是一个小代码示例,用于说明我的64位Linux系统上的奇怪行为。

// compile with `gcc -o weird_shift_behaviour weird_shift_behaviour.c`

#include <stdio.h>

int main(void){
    long long foo = 0;
    long long bar = 0;
    int i;
    puts("<foo> will be set to all 1s by repeatedly shifting 1 to the left and OR-ing the result with <foo>.");
    puts("<bar> will be set to all 1s by repeatedly OR-ing it with 1 and shifting <bar> to the left one step.");
    for(i=0;i<8*(int)sizeof(long long)-1;++i){
        foo |= (1<<i);
        bar = bar<<1 | 1;
        printf("<i>: %02d <foo>: %016llx <bar>: %016llx \n",i,foo,bar);
    }
    return 0;
}

我知道这不是在C中为所有1设置整数类型的规范方法,但我确实尝试过。以下是示例程序生成的输出的有趣部分:

<i>: 29 <foo>: 000000003fffffff <bar>: 000000003fffffff 
<i>: 30 <foo>: 000000007fffffff <bar>: 000000007fffffff 
<i>: 31 <foo>: ffffffffffffffff <bar>: 00000000ffffffff 
<i>: 32 <foo>: ffffffffffffffff <bar>: 00000001ffffffff 

为什么会发生这种奇怪的行为?到目前为止,我想不出任何合理的解释。

1 个答案:

答案 0 :(得分:5)

1<<i
1为32位宽时,

int的类型为1 << 31int为未定义的行为。

来自C标准:

  

(C99,6.5.7p4)“E1&lt; E2的结果是E1左移E2位位置;空位用零填充。[...]如果E1具有有符号类型和非负值,并且E1 x 2 ^ E2在结果类型中是可表示的,那么这就是结果值;否则,行为是未定义的。“

要解决您的问题,请使用1<<i更改1ULL << i