【问题标题】:Arithmetic right-shift of signed integer有符号整数的算术右移
【发布时间】:2016-03-30 14:30:10
【问题描述】:

C99 规范指出:

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

我很想知道,哪些实现/编译器不会将签名的E1 >> 31 视为一堆11111....

【问题讨论】:

  • 少数 -1 不是 1111....,还有很多 int 不是 32 位的。
  • 注意:不要使用过时的标准版本。 C 标准是 C11,而不是 C99。说起来,文字很清楚。如果您希望代码可移植,请不要依赖它。请注意,班次也可以调用未定义的行为。参见标准中的 6.5.7p3(即唯一有效的版本)。
  • 还有许多 32 位二进制补码实现,它们忽略签名并产生 1 作为结果。该标准实际上措辞谨慎,以避免指定 >> 是执行算术移位还是逻辑移位。

标签: c c99 bit-shift


【解决方案1】:

大多数用于微控制器的嵌入式编译器倾向于支持逻辑移位(零移位)而不是算术移位(符号位移位)。

这可能是因为带符号的数字在嵌入式系统中很少见,因为这种编程比使用屏幕的桌面编程更接近硬件,离用户更远。

签名数字毕竟只是用户演示。如果您不需要向用户打印数字,那么您根本不需要经常签名的数字。

当然,一开始就对有符号数使用 shift 并没有任何意义。在我的编程生涯中,我从来没有遇到过需要这样做的场景。这意味着在大多数情况下,这种转变只是偶然的错误。

【讨论】:

  • @Lundin 我正在使用一些加密代码,它利用算术右移作为删除 if 语句的一种方式。谢谢你的回答。
  • @MarkP 哦,但是如果可移植性很重要,您肯定需要重新考虑该算法。
  • @Lundin 是的,这就是问题的核心。此代码不太可能在微控制器上运行。主要担心的是那里有大型计算机无法处理这种情况。
  • @Lundin 即使有符号整数是 2 的补码,并且右移是算术右移,当被操作的值既是负数又是奇数时,除以 2 与右移不同。除法向零截断,但算术右移向负无穷大截断。
【解决方案2】:

您可以在不使用if 语句的情况下,使用无符号类型模拟有符号、2 的补码算术右移。例如:

#include <limits.h>

unsigned int asr(unsigned int x, unsigned int shift)
{
    return (x >> shift) | -((x & ~(UINT_MAX >> 1)) >> shift);
}

您可能需要在代码中使用不同的无符号类型及其关联的最大值。

【讨论】:

  • 这与问题有什么关系?
  • @Lundin 与问题有关,但没有直接回答问题。很难将代码放在普通注释中。它有点像一个 X Y 问题来回答它。如果不能靠&gt;&gt;做算术右移,那怎么便携呢?
猜你喜欢
  • 1970-01-01
  • 2011-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多