【问题标题】:Signed right shift: which compiler use logical shift有符号右移:哪个编译器使用逻辑移位
【发布时间】:2011-09-23 04:39:50
【问题描述】:

我使用 Visual Studio、Ubuntu 的 GCC、Intel 编译器、MinGW 测试了右移。全部移位符号位。我猜 Xcode 的 GCC 也是如此。

我知道该行为是特定于实现的,但看起来所有主要的桌面/服务器编译器都实现了算术移位。是否有任何广泛使用的编译器不会改变符号位?

谢谢。

【问题讨论】:

  • 实现定义的行为正是由实现定义的。位移位用于将值视为位的集合。有符号数并不意味着被视为位的集合。使用无符号值。或者如果你想除以二,然后除以二 - 不要使用移位。如果该优化有效,编译器将为您完成。另见securecoding.cert.org/confluence/display/cplusplus/…
  • 等等,你是说在 C++ 中右移一个无符号值是标准未定义的?!不知道...
  • 问题是除以 2 的行为与算术右移不同。因此,如果您使用除法,编译器无法将其更改为移位,并且如果您想要带符号的移位行为,则在 C 中没有简单、可移植的方式来表达它
  • @Mehrdad:这是实现定义的 signed 值的右移...无符号值很好。 @ pic11:顺便说一句-不仅仅是符号位是否“移入”,还在于新的 m.s.b.是 0 或 1(当然,对于实现定义的行为,可能会出现一些异常情况,结果不是上述情况:-/)。
  • 你最好不要不知道也不关心。这样一来,您就不会意外编写不可移植的代码。

标签: c++ c bit-shift implementation-defined-behavior


【解决方案1】:

Cray C 编译器默认对有符号值进行逻辑右移,但可以选择进行算术移位。

一般来说,假设有符号右移是算术运算是安全的。

【讨论】:

  • 如果你有一些关于轮班行为的引用会更好
【解决方案2】:

据我所知,>> 运算符进行算术移位。然而,对有符号和无符号整数执行移位的方式有所不同 - 有符号将扩展 MSB(通常是符号位)而无符号则不会(它们始终为非负数,因此符号位始终为零)。

编辑:将“通常”应用于我上面写的所有内容;)。

【讨论】:

  • C 标准的字面意思是:“如果 E1 具有带符号类型和负值,则结果值是实现定义的。”。所以你最好检查一下它在你所有的目标架构上是如何工作的(但是你很有可能没问题)。
【解决方案3】:

C 在许多不同的架构上运行。我的意思是很多不同的架构。您可以在嵌入式 DSP 和 Cray 超级计算机上运行 C 代码。

人们认为理所当然的 C 标准的大多数“实现定义”部分实际上只会在晦涩的架构上中断。例如,在 DSP 和 Cray 超级计算机中,CHAR_BIT 是 32 或 64 之类的巨大数字。因此,如果您在 x86 上尝试您的代码,或者如果您对 PowerPC、ARM 或 SPARC 很慷慨,那么您就是不太可能遇到任何真正奇怪的情况。没关系。如今,大多数代码将始终在具有二进制补码整数和算术移位的面向字节的体系结构上运行。我毫不怀疑在可预见的未来任何新的 CPU 架构都将是相同的。

但是让我们看一下整数的两种最常见的表示形式:二进制补码和一个补码:

switch ((-1) >> 1) {
case 0:
case -0:
    puts("Hello, one's complement world!");
    // Possibly sign-magnitude.
    break;
case -1:
    puts("Hello, two's complement world!");
    break;
default:
    puts("Hello, computer without arithmetic shift");
    break;
}

别着急。当你想分割时坚持/,当你需要转移时坚持>>。即使是糟糕的编译器也擅长优化这些操作。 (请记住,如果 x 为负数,则 x/2 != x>>1 是负数,除非您使用的是反码机,这几乎肯定不是真的。)

该标准确实保证如果(int) x 不是负数,那么(int) x >> n == (unsigned) x >> n,因此编译器没有太多空间来做完全出乎意料的事情。

【讨论】:

  • 我试过你的代码。我运行的所有编译器都实现了算术移位。
  • @pic11:改变你的编译器不会做任何事情,这正是我要说的。您需要更改为互补架构才能看到差异。
  • 如果需要,DeathStation 9000 编译器可以在 x86 上免费使用 shr 而不是 sar。 C标准只是说它是“实现定义的”,而不是2的补码系统必须使用算术移位。 (与您关于健全的 CPU 的观点类似,许多 C 都假定健全/有用的实现选择。仅仅符合标准不足以使 C 编译器可用于现实生活中的大部分内容。有时写作完美可移植代码不值得麻烦或它会导致膨胀,因为 ISO C 在某些方面过于可移植。)
【解决方案4】:

通常它更多地取决于编译器使用的目标架构。如果拱门同时具有算术(有符号)和逻辑(无符号)移位指令,则该拱门的 C 编译器将使用合适的。另一方面,如果它只有逻辑移位,C 编译器将只使用它,即使它没有为负值“做正确的事情”,因为 C 规范允许编译器做任何事情。

【讨论】:

    猜你喜欢
    • 2017-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 2014-09-11
    • 1970-01-01
    相关资源
    最近更新 更多