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

是否有任何2补码平台/编译器,其中有符号移位不做通常的事情?

  •  5
  • geza  · 技术社区  · 6 年前

    左移的结果可能是 undefined behavior :

    位是零填充的。如果E1具有无符号类型,则 在结果类型中可表示。否则,如果E1有符号类型 非负值,E12^E2在 结果类型的相应无符号类型,然后是该值, 转换为结果类型,是结果值;否则 行为未定义。

    implementation-defined :

    E2的值是E1右移的E2位位置。如果E1有 无符号类型,或者如果E1具有有符号类型和非负值, E1/2^E2。如果E1有符号类型和负值,则

    现在,我所知道的所有平台,未定义的行为/实现定义,实际上在这里做了一些明智的事情:

    • 左移一个负数等于乘以2^E2,就像这个数是正数一样
    • 右移负数是“算术移位”,它通常移位数字,但将符号位放入最有效位。

    2-补体 平台/编译器,哪一个不是这样的?


    为什么问这个问题?大多数编译器 don't emit optimal code (链接由phuclv提供,查看 test1 test2 )对于中的二次幂除法 certain circumstances (不过,clang生成了最佳代码)。

    1 回复  |  直到 6 年前
        1
  •  1
  •   supercat    6 年前

    一些处理器的编译器缺少扩展右移指令的符号,它们将所有右移操作都作为零填充处理。

    C99标准将负左移更改为未定义的行为。基本原理中没有给出任何改变的理由,甚至也没有承认这一点。基本原理中没有提到这一点,这表明它并没有被视为一个突破性的变化,因为没有理由期望在C89下有效定义行为的任何实现不会继续以同样的方式定义行为,不管标准是否继续要求它。唯一有意义的意图是允许一个“补码”或“符号大小”实现(如果曾经为C99生成过任何补码)以比C89所要求的更有用的方式运行。

    在实践中,我所知道的编译器中,目前唯一不遵守左移位的期望,其结果可以表示为不溢出的乘法,这些编译器被显式配置为在负左移位时发出嘎嘎声,纯粹是因为标准不再定义它们的行为。然而,如果一些“聪明”的人基于标准不再适用的事实来“优化”一个二补编译器,我就不会感到特别惊讶了 要求 这些平台的实现以它们一贯的合理和有用的方式运行。这种偏差有两种形式:

    1. 编译器可以决定,如果一个要求进位标志为clear的操作前面有一个带符号的左移位,则可以省略通常位于后一个操作之前的“clear carry”指令。我曾经使用过可以保存指令的平台,但我看到的所有用于此类平台的编译器都清除了进位,即使标准不需要它。

    2. 编译器可以决定左移位的结果为负值是“不可能”的,因此可以安全地省略该结果与任何负值之间的任何比较。更进一步说,它可以决定操作数也不可能是负数,并删除与负数的任何比较,这些比较不会阻止执行左移位。gcc和clang都还没有试图实施这种优化,但这并不意味着他们永远不会这样做。