【问题标题】:Strange equality check using bitwise shift operators使用按位移位运算符进行奇怪的相等检查
【发布时间】:2012-12-19 11:44:58
【问题描述】:
#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

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

【问题讨论】:

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


    【解决方案1】:

    这不是相等检查(从结果中可以清楚地看到),这是一个赋值:

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

    相等性检查很简单

    a == b;
    

    【讨论】:

    • 但是,如果它是简单的分配,那么foo() 如何能够正确输出所有正输入? (上面有问题的示例输出)
    • @Manav 巧合?你为什么要这个?普通的旧 == 有什么问题?
    • foo() 似乎与个位数数字完美搭配 :)
    • @Manav:如果左移溢出,表达式只能返回 1,在这种情况下行为未定义。如果您尝试不会导致溢出的一位数 (0,1,2,3),那么您应该会发现 foo(2,2) 返回 0。
    【解决方案2】:

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

    答案在于 C99 标准(ISO C99:6.5.7 位移位运算符):

    /4. E1 &lt;&lt; E2 的结果是E1 左移E2 位位置;空出的位被填充 零。如果E1 有无符号类型,则结果的值为E1 × 2E2,减少模 比结果类型中可表示的最大值大一。如果E1 有一个签名 类型和非负值,E1 × 2E2 可以在结果类型中表示,那么就是 结果值;否则,行为未定义。

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

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

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

    【讨论】:

    • @Manav :这也是未定义的行为,因为移动的位数超过实际占用的位数,行为未定义
    【解决方案3】:

    尝试更多值:

    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 为零,否则它总是返回零,除非左移溢出,在这种情况下,行为再次未定义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-15
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多