评估不同结果的两条等效线[比特移位]

时间:2014-09-10 23:03:06

标签: c

我在函数上调用此代码,以便将signed int n设置为零,但它的行为很奇怪。

printf("n is %d \n", n);                                                                                                                                                                                                               
printf("shift1 %d \n", -1 << (32 + (~0 + 1)));
printf("shift2 %d \n", -1 << (32 + (~n + 1)));

打印

n is 0
shift1 0
shift2 -2

我不知道为什么会发生这种情况,因为n == 0。

3 个答案:

答案 0 :(得分:3)

它的行为很奇怪,因为应用于负整数的<<运算符的行为是未定义的。因此,任何结果都是此代码的有效结果。

由于没有定义行为,我们无法对其进行推理。所以我们不能说为什么它有所不同,只是根据C规范它允许不同。

当我尝试时,由于两次换班,我得到零。 (我们的结果都不正确!这只是为了表明调用未定义行为的同一程序确实可以在不同的编译器和/或体系结构上产生不同的结果。)

答案 1 :(得分:1)

在任何情况下,在任何方向上移动任何数量(甚至0)的负数始终为Undefined Behavior (UB)
移位有符号值使得数学结果无法存储在其类型中也是如此。

无法解释未定义的行为。

答案 2 :(得分:1)

即使将-1更改为1(使用Visual Studio,在DEBUG配置中),我也可以重现差异:

printf("n is %d \n", n);
printf("shift1 %d \n", 1 << (32 + (~0 + 1)));
printf("shift2 %d \n", 1 << (32 + (~n + 1)));

对于第一行,我收到warning

  

警告C4293:'&lt;&lt;' :轮班计数为负数或太大,未定义的行为

关键是在第一种情况下,我的编译器在编译时计算表达式并看到操作数太大,在第二种情况下 - 在运行时。

就我而言,在编译时,表达式在运行时被评估为01

int n = 0;
    mov         dword ptr [n],0

auto x = 1 << (32 + (~0 + 1));
    mov         dword ptr [x],0  

auto y = 1 << (32 + (~n + 1));
    mov         ecx,dword ptr [n]  
    not         ecx  
    add         ecx,21h  
    mov         eax,1  
    shl         eax,cl  
    mov         dword ptr [y],eax  

RELEASE模式下,两个结果都相同。