(-1 >> 1)== -1 - 为什么?

Fra*_*k V 7 c bit-shift

为什么会(-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;
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*one 23

因为有符号整数用二进制补码表示.

-111111111(如果它是一个8位数字).

-1 >> 1显然标志延伸,以便它仍然存在11111111.这种行为取决于编译器,但对于Microsoft,当右移(#(>>)符号位时,符号位被复制,而右移无符号数会导致a 0被置于最左边的位.

  • 它不是未定义的行为,它的实现定义了符号位是否以带符号的右移进行. (11认同)
  • 这是C中未定义的行为,注意. (4认同)
  • 对于那些想要查找的人,在C99标准中为6.5.7/5. (3认同)
  • 对于那些不知道的人,实现定义意味着实现(即编译器和工具链)可以做任何想做的事情,但必须_documented_. (3认同)

Wad*_* M. 11

一个算术右移移位时,将保留标志符号数:

11111111 (-1) will stay 11111111 (-1) 
Run Code Online (Sandbox Code Playgroud)

相反,逻辑右移不会保留标志:

11111111 (-1) will become 01111111 (127)
Run Code Online (Sandbox Code Playgroud)

您的代码清楚地执行算术移位,因此重复符号位(MSB).运算符(>>)的作用取决于您正在使用的平台的实现细节.在大多数情况下,这是算术转换.

另外,请注意,11111111根据表示,可以有两种不同的含义.这也会影响他们的转变方式.

  • 如果是无符号,则11111111表示255.向右移动不会保留符号,因为MSB不是符号位.
  • 如果签名,则11111111表示-1.算术上将它向右移动将保留标志.


bdo*_*lan 5

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

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

发生这种情况的原因很可能是因为您的编译器使用x86 SAR(Shift Arithmetic Right)指令来实现>>.这意味着将发生符号扩展 - 一旦值被移位,最高有效位将被复制到新的MSB中.来自intel手册:

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

  • 左移有符号整数可以是未定义的(如果它是负的)或定义良好的(如果它是正数且结果是可表示的则与无符号相同).它只是右移一个实现定义的负数. (2认同)