为什么(-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;
}
答案 0 :(得分:23)
因为有符号整数用two's complement表示法表示。
-1
将为11111111
(如果是8位数字)。
-1 >> 1
显然会签名延伸,以便保持11111111
。此行为取决于编译器,但对于Microsoft,当向右移位有符号数字(>>
)时,将复制符号位,而向右移位无符号数会导致0
被置位在最左边的位。
答案 1 :(得分:11)
转换Arithmetic right shift后,signed number会保留标志:
11111111 (-1) will stay 11111111 (-1)
相反,Logical right shift不会保留标志:
11111111 (-1) will become 01111111 (127)
您的代码显然会进行算术移位,因此重复符号位(MSB)。运算符(&gt;&gt;)的作用取决于您正在使用的平台的实现细节。在大多数情况下,这是算术转换。
另请注意,11111111
可能有两种不同的含义,具体取决于表示形式。这也影响了他们的转变方式。
11111111
代表255.向右移动将不会保留符号,因为MSB不是符号位。 11111111
代表-1。算术上将它向右移动将保留标志。答案 2 :(得分:5)
将负数移位是C中的实现行为。结果将取决于您的平台,理论上可能完全没有意义。根据C99标准(6.5.7.5):
E1&gt;的结果&gt; E2是E1 右移E2位位置。如果E1 有一个无符号类型或E1有一个 签名类型和非负值, 结果的值是 E1 /的商的组成部分 2 ^ E2。如果E1有签名类型和 负值,结果值是 实施德音响定义
发生这种情况的原因很可能是因为您的编译器使用x86 SAR(Shift算术右)指令来实现&gt;&gt;。这意味着将发生符号扩展 - 一旦值被移位,最高有效位将被复制到新的MSB中。来自intel manuals:
移位算术权(SAR)和 移位逻辑右(SHR)指令 移动目的地的位 操作数向右(朝向更少 重要的位置)。对于每一个 移位计数,最低有效位 目标操作数的移位 进入CF旗帜,最多 有效位是设置或 根据指示清除 类型。 SHR指令清除了 最重要的位(见图7-8 在英特尔®64和IA-32中 架构软件开发人员 手册,第1卷); SAR指令 设置或清除最重要的 位对应于符号(大多数 有意义的原始值 在目标操作数中。 实际上, SAR指令填空 位位置的移位值 未移位价值的标志(见 图64中的Intel®64和IA-32 架构软件开发人员 手册,第1卷)。
答案 3 :(得分:3)
当你右移并且最左边的位是1时,一些平台/编译器将引入0并且一些将保留1并且使新的最左位为1.这保留了数字的符号所以负数保持消极,称为符号扩展。
如果你尝试((unsigned) -1) >> 1
,你会看到差异,它将进行无符号右移,因此总是会移位0位。
答案 4 :(得分:1)
签署延期。