38

我有 C 代码,我在其中执行以下操作。

int nPosVal = +0xFFFF;   // + Added for ease of understanding
int nNegVal = -0xFFFF;   // - Added for valid reason

现在当我尝试

printf ("%d %d", nPosVal >> 1, nNegVal >> 1);

我明白了

32767 -32768

这是预期的吗?

我能想到类似的东西

65535 >> 1 = (int) 32767.5 = 32767
-65535 >> 1 = (int) -32767.5 = -32768

也就是说,-32767.5 四舍五入为 -32768。

这种理解正确吗?

4

6 回答 6

52

看起来您的实现可能正在使用二进制补码进行算术位移。在这个系统中,它将所有位向右移动,然后用最后一位的副本填充高位。因此,对于您的示例,在这里将 int 视为 32 位:

nPosVal = 00000000000000001111111111111111
nNegVal = 11111111111111110000000000000001

换班后,你有:

nPosVal = 00000000000000000111111111111111
nNegVal = 11111111111111111000000000000000

如果将其转换回十进制,则分别得到 32767 和 -32768。

实际上,右移向负无穷大方向移动。

编辑: 根据最新草案标准的第 6.5.7 节,负数的这种行为取决于实现:

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

他们对此表示合理

C89 委员会确认了 K&R 授予的实现自由,不需要符号右移操作来符号扩展,因为这样的要求可能会减慢快速代码,并且符号扩展移位的有用性是微不足道的。(将负的二​​进制补码整数在算术上右移一位除以二不同!)

所以它在理论上依赖于实现。在实践中,我从未见过在左操作数有符号时不进行算术右移的实现

于 2009-12-07T05:18:42.597 回答
21

不,当使用整数时,你不会得到像 0.5 这样的小数。当您查看两个数字的二进制表示时,可以很容易地解释结果:

      65535: 00000000000000001111111111111111
     -65535: 11111111111111110000000000000001

向右移动一位,向左扩展(请注意,这取决于实现,感谢 Trent):

 65535 >> 1: 00000000000000000111111111111111
-65535 >> 1: 11111111111111111000000000000000

转换回十进制:

 65535 >> 1 = 32767
-65535 >> 1 = -32768
于 2009-12-07T05:18:25.250 回答
9

C 规范没有指定符号位是否移位。它取决于实现。

于 2009-12-07T05:15:36.473 回答
3

当您右移时,最低有效位被丢弃。

0xFFFF = 0 1111 1111 1111 1111,右移得到 0 0111 1111 1111 1111 = 0x7FFF

-0xFFFF = 1 0000 0000 0000 0001(2s 补码),右移到 1 1000 0000 0000 0000 = -0x8000

于 2009-12-07T05:14:47.223 回答
3

A-1:是的。0xffff >> 1 是 0x7fff 或 32767。我不确定 -0xffff 的作用。这很奇特。

A-2:移位与除法不同。它是位移——一种原始的二进制操作。它有时可用于某些类型的除法很方便,但并不总是相同。

于 2009-12-07T05:18:16.093 回答
2

在 C 级别之下,机器有一个完全为 integer 或scalar的 CPU 内核。尽管现在每个台式机 CPU 都有一个 FPU,但情况并非总是如此,即使在今天,嵌入式系统也没有浮点指令。

今天的编程范例和 CPU 设计和语言可以追溯到 FPU 甚至可能不存在的时代。

因此,CPU 指令实现定点操作,通常被视为纯整数操作。只有当程序声明浮点数精度项时,才会存在任何分数。(好吧,您可以将 CPU 操作用于带有分数的“定点”,但现在而且一直很少见。)

无论几年前语言标准委员会要求什么,所有合理的机器都会在有符号数的右移时传播符号位。无符号值的右移左移零。向右移出的位被丢弃在地板上。

为了进一步理解,您需要研究“补码算术”。

于 2009-12-07T05:23:06.180 回答