使用按位移位运算符进行奇怪的等式检查

时间:2012-12-19 11:44:59

标签: c++ c linux operators bit-manipulation

#include <stdio.h>

int foo(int a, int b)
{
        return ((a>>= b<<= a) ? 1 : 0);
}

void bar(int x, int y)
{
        printf("%d,%d: %s\n",x, y, (foo(x,y) ? "Equal" : "Not Equal"));
}

int main()
{
        bar(0,1);
        bar(4,4);
        bar(3,2);
        bar(9,9);
        bar(-2,-2);
        bar(-8,8);
        return 0;
}

上述程序的输出是

0,1: Not Equal
4,4: Equal
3,2: Not Equal
9,9: Equal
-2,-2: Equal
-8,8: Equal

您能帮助我理解函数foo()中等式检查的工作原理吗?当一个论点是积极的而另一个是否定的时候,为什函数foo()中的解决方法是为所有情况正确显示结果,即所有消极和正面参数?

编辑:根据以下答案,其他值的结果为:

70,72: Equal
-2,-2: Equal
64,64: Equal
128,32: Equal
256,250: Not Equal
250,256: Equal
-250,-256: Equal

请解释一下,为什么这种平等检查适用于某些价值集,而不适用于其他价值集。里面发生了什么?

3 个答案:

答案 0 :(得分:7)

这不是一次平等检查(你可以从结果中清楚地看到),这是一项任务:

a = ( a >> ( b = b << a ) );  //results in UB for negatives

等式检查很简单

a == b;

答案 1 :(得分:5)

  

为什么当一个论点是积极的而另一个是否定的时候会失败?   函数foo()中的解决方法是为所有情况正确显示结果,即所有消极和正面参数?

答案在于C99-Standard(ISO C99:6.5.7按位移位运算符):

  

/ 4。 E1 << E2的结果是E1左移E2位位置;腾出的位充满了   零。如果E1具有无符号类型,则结果的值为E1 × 2E2,减少模数   比结果类型中可表示的最大值多一个。如果E1已签名   类型和非负值,E1 × 2E2可在结果类型中表示,然后就是   结果价值;否则,行为未定义。

所以foo(-2,-2)未定义的行为

  

/ 5。 E1 >> E2的结果是E1右移E2位位置。如果E1具有无符号类型   或者如果E1具有签名类型和非负值,则结果的值为整数   E1 / 2E2的商的一部分。如果E1具有签名类型和负值,则   结果值是实现定义的。

所以foo(-8,8)实现定义的

答案 2 :(得分:4)

尝试更多值:

1,0: Equal
0,0: Not Equal
1,1: Not Equal
2,2: Not Equal
3,3: Not Equal

表示根本不是等号检查。

表达式具有未定义的行为,因为它执行a的两个未经测序的修改。如果我们假设你的编译器对它进行评估,好像在左移之后有一个序列点,即

b <<= a;
a >>= b;
return a ? 1 : 0;

然后很容易看出,除非b为零,否则它总是返回零,除非左移溢出,在这种情况下行为再次未定义。