7

为什么会(-1 >> 1)导致-1?我在 C 中工作,但我认为这不重要。

我无法弄清楚我错过了什么......

下面是一个执行计算的 C 程序示例:

#include <stdio.h>



int main()
{
    int num1 = -1;

    int num2 = (num1 >> 1);

    printf( "num1=%d", num1 );

    printf( "\nnum2=%d", num2 );

    return 0;
}
4

5 回答 5

23

因为有符号整数以二进制补码表示法表示。

-1将是11111111(如果它是一个 8 位数字)。

-1 >> 1显然 符号 延伸 以 使其 保留11111111. 此行为取决于编译器,但对于Microsoft 而言,将有符号数右移 ( >>) 时,符号位会被复制,而无符号数右移会导致将 a0放入最左边的位。

于 2009-06-26T01:38:04.120 回答
11

移动有符号数时,算术右移将保留符号:

11111111 (-1) will stay 11111111 (-1) 

相反,逻辑右移不会保留符号:

11111111 (-1) will become 01111111 (127)

您的代码显然进行了算术移位,因此重复了符号位( MSB )。运算符 (>>) 的作用取决于您使用的平台的实现细节。在大多数情况下,它是算术移位。

另外,请注意,11111111根据表示形式,它可能有两种不同的含义。这也会影响他们转移的方式。

  • 如果无符号,11111111则表示 255。将其向右移动不会保留符号,因为 MSB 不是符号位。
  • 如果有符号,则11111111表示 -1。算术将其向右移动将保留符号。
于 2009-06-26T01:42:02.100 回答
5

将负数移位是 C 中的实现行为。结果将取决于您的平台,理论上可能完全没有意义。从 C99 标准(6.5.7.5):

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

发生这种情况的原因很可能是因为您的编译器使用 x86 SAR(算术右移)指令来实现 >>。这意味着将发生符号扩展 - 一旦值移位,最高有效位将被复制到新的 MSB 中。从英特尔手册

算术右移 (SAR) 和逻辑右移 (SHR) 指令将目标操作数的位向右移动(朝向较低有效位位置)。对于每个移位计数,目标操作数的最低有效位被移入 CF 标志,最高有效位根据指令类型设置或清除。SHR 指令清除最高有效位(参见英特尔® 64 和 IA-32 架构软件开发人员手册第 1 卷中的图 7-8);SAR 指令设置或清除最高有效位以对应目标操作数中原始值的符号(最高有效位)。实际上,SAR 指令用未移位值的符号填充空位位置的移位值(参见英特尔® 64 位和 IA-32 架构软件开发人员手册第 1 卷中的图 7-9)。

于 2009-06-26T01:36:40.940 回答
3

当您右移并且最左边的位为 1 时,一些平台/编译器将带入 0,而一些平台/编译器将保留 1 并使新的最左边位为 1。这将保留数字的符号,因此负数保持负数并且称为符号扩展。

如果您尝试((unsigned) -1) >> 1,您会看到不同之处,这将执行无符号右移,因此将始终移入 0 位。

于 2009-06-26T01:38:30.360 回答
1

标志扩展。

于 2009-06-26T01:35:45.997 回答