代码之家  ›  专栏  ›  技术社区  ›  izac89

两个相同的右移表达式产生不同的结果

  •  1
  • izac89  · 技术社区  · 5 年前

    我刚查了一下 C++ 标准下面的代码似乎不应该被删除 undefined behavior :

    unsigned int val = 0x0FFFFFFF;
    unsigned int res = val >> 34;  // res should be 0 by C++ standard,
                                   // but GCC gives warning and res is 67108863
    

    根据标准:

    E1的值>>E2是E1右移位的E2位位置。 如果E1 具有无符号类型,或者如果E1具有有符号类型和非负 值,结果的值是 E1/2^E2。 如果E1有符号类型和负值,则结果为 价值是实现密集型的。

    根据标准,因为34不是负数,所以变量 res 将是0。

    GCC对代码段给出以下警告,并且 物件 67108863 :

    警告:右移计数>=字体宽度

    我还检查了GCC发出的汇编代码。它只是打电话 SHRL ,以及针对SHRL的英特尔指令文档 物件 不是零。

    那么,这是否意味着GCC不在英特尔平台上实现标准行为?

    0 回复  |  直到 12 年前
        1
  •  46
  •   Shafik Yaghmour    12 年前

    这个 draft C++ standard 分段 5.8 值班员 在段落中 1. 说( 强调我的 ):

    结果的类型是提升的左操作数的类型。 如果正确的操作数 是否定的,或者 大于或等于提升后的左操作数的位长度 .

    所以如果 无符号整型 32 bits 或者这是未定义的,这正是警告 gcc 是给你的。

        2
  •  19
  •   Mats Petersson    12 年前

    要准确解释发生了什么: 编译器将加载 34 输入一个寄存器,然后将常数输入另一个寄存器,并对这两个寄存器执行右移操作。x86处理器对移位值执行“shiftcount%位”,这意味着您将得到2的右移。

    因为0x0FFFFF(268435455十进制)除以4=67108863,这就是你看到的结果。

    如果你有一个不同的处理器,比如PowerPC(我想),它可能会给你零。