我最近发现在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
为什么会发生这种奇怪的行为?到目前为止,我想不出任何合理的解释。
答案 0 :(得分:5)
1<<i
当1
为32位宽时, int
的类型为1 << 31
且int
为未定义的行为。
来自C标准:
(C99,6.5.7p4)“E1&lt; E2的结果是E1左移E2位位置;空位用零填充。[...]如果E1具有有符号类型和非负值,并且E1 x 2 ^ E2在结果类型中是可表示的,那么这就是结果值;否则,行为是未定义的。“
要解决您的问题,请使用1<<i
更改1ULL << i
。