为什么会(-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;
}
因为有符号整数以二进制补码表示法表示。
-1
将是11111111
(如果它是一个 8 位数字)。
-1 >> 1
显然 符号 延伸 以 使其 保留11111111
. 此行为取决于编译器,但对于Microsoft 而言,将有符号数右移 ( >>
) 时,符号位会被复制,而无符号数右移会导致将 a0
放入最左边的位。
11111111 (-1) will stay 11111111 (-1)
相反,逻辑右移不会保留符号:
11111111 (-1) will become 01111111 (127)
您的代码显然进行了算术移位,因此重复了符号位( MSB )。运算符 (>>) 的作用取决于您使用的平台的实现细节。在大多数情况下,它是算术移位。
另外,请注意,11111111
根据表示形式,它可能有两种不同的含义。这也会影响他们转移的方式。
11111111
则表示 255。将其向右移动不会保留符号,因为 MSB 不是符号位。11111111
表示 -1。算术将其向右移动将保留符号。将负数移位是 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)。
当您右移并且最左边的位为 1 时,一些平台/编译器将带入 0,而一些平台/编译器将保留 1 并使新的最左边位为 1。这将保留数字的符号,因此负数保持负数并且称为符号扩展。
如果您尝试((unsigned) -1) >> 1
,您会看到不同之处,这将执行无符号右移,因此将始终移入 0 位。
标志扩展。