Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否有任何2-complete平台/编译器,其中符号移位不';你不能做平常的事吗?_C++_Undefined Behavior - Fatal编程技术网

C++ 是否有任何2-complete平台/编译器,其中符号移位不';你不能做平常的事吗?

C++ 是否有任何2-complete平台/编译器,其中符号移位不';你不能做平常的事吗?,c++,undefined-behavior,C++,Undefined Behavior,左移的结果可能是: E1>E2的值是E1右移位的E2位位置。如果E1有 无符号类型,或者如果E1具有有符号类型和非负值, 结果的值是的商的整数部分 E1/2^E2。如果E1具有有符号类型和负值,则结果为 值是实现定义的 现在,我知道的所有平台,未定义的行为/定义的实现,实际上都在这里做一些合理的事情: 左移一个负数等于乘以2^E2,就像这个数是正数一样 将负数右移是“算术移位”,它通常将数字移位,但将符号位放入最高有效位 所以,问题是,是否有任何2-complete平台/编译器的行为不是这样

左移的结果可能是:

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

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

  • 左移一个负数等于乘以2^E2,就像这个数是正数一样
  • 将负数右移是“算术移位”,它通常将数字移位,但将符号位放入最高有效位
所以,问题是,是否有任何2-complete平台/编译器的行为不是这样的



为什么要问这个问题?大多数编译器(phuclv提供的链接,查看
test1
test2
之间的反汇编)中的二次幂除法(虽然clang生成最佳代码)。

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

C89标准精确地定义了在所有一补或二补平台上左移负数的行为,这些平台在有符号或无符号类型上都不使用填充位。然而,一补机器上的行为并不等同于乘法。此外,符号大小机器上的正确行为尚不清楚

C99标准将负左移改为未定义行为。基本原理中没有任何内容为这一变化提供任何理由,甚至也没有承认这一点。基本原理中没有提到这一点,这表明它没有被视为一个突破性的变化,因为没有理由期望任何根据C89有效定义行为的实现不会继续以同样的方式定义行为,无论标准是否继续要求它。唯一有意义的意图是允许1’-补码或符号大小实现(如果为C99生成了任何实现)以一种可能比C89所要求的更有用的方式运行

在编写C89甚至C99时,作者没有发现标准强制执行行为的操作与标准是否要求实现以可预测且有用的方式处理的操作之间有多大区别。编撰者似乎相信委员会打算从语言中消除后一种形式的所有行为,但我没有看到任何证据表明这类行为

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

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

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


  • 两个s-complete系统的高质量实现将以可预测的方式处理有符号的左移,除非或直到有特别令人信服的理由让他们这样做——这似乎是不太可能发生的。至于低质量的实现可能会做些什么,谁知道呢。

    -不,2的补充定义必须是这样的(这只是数学计算的结果),这大概就是它最终主宰行业的原因。顺便说一句,由于C标准所要求的截断语义,2除法的幂没有被优化为移位有符号整数的问题通常来自这样一个事实,即它不是同一件事-3/2=-1,而-3>>1=-2。@MatteoItalia:在这个例子中,它们是相同的,因为除法是精确的。引用文本的整个要点是指出第一个项目符号是不正确的。不管怎样,它似乎起作用,这是一种太常见的意外。第一个int32_t值是0b10111…111,即-1073741825,其中单个左移位会损坏数字。你不需要精品硬件就能看到问题,试试看。@HansPassant:你举个例子,当数字溢出时。当然,这不可能是正确的。一个简单的
    *2
    对于这个数字也不正确。但是如果它没有溢出,那么在我所知道的所有2-complete平台上都是正确的。回答很好,谢谢!我没想到我们需要回到C89/C99来回答这个问题。很好的优化例子!