有符号整数的右移

4
#include<stdio.h>

int main()
{
  int num;

  printf("enter the number\n");
  scanf("%d",&num);

  int a,b;
  printf("enter the number of bits yiu want to shift\n");
  scanf("%d",&b);

  a=num>>b;

  printf("a is=%d\n",a);

  return 0;
}

对于正数num,我得到了预期的结果。但是,在我的程序中进行dry run时,使用负值num时无法找到答案。 以num=-1为例子: 所以-1将被表示为1111111111111111,并将其右移1位应该产生输出0111111111111111,即十进制形式的32767。但输出为-1。


@barakmanos 使用该定义,我期望输出为32767。 - user2738777
1
@barakmanos:你指的是哪个定义?C标准并没有这样说;它说结果是实现定义的(请参见R Sahu的答案;他比我先回答了)。 - Keith Thompson
@barakmanos:我不知道。如果我需要使用移位运算符,我会尝试仅将它们应用于无符号类型。 - Keith Thompson
@barakmanos 示例侧边栏:尽管旧机器正在退出使用,但它生成的数据校验和取决于旧机器的非2补数移位和有符号零。因此,为了继续检查和生成相同的校验码 - 因为数据格式仍在使用中 - 我的2补数机器需要模拟带符号整数运算以获得正确的校验码。现在,如果那台机器没有使用UB,这将不是一个现代问题。 - chux - Reinstate Monica
@KeithThompson:我们通常只对“unsigned”操作数应用移位(由于需要移位的任务的典型性质,例如位掩码等)...但是这仍然让我想到了所有那些情况,在这些情况下,我有意地对“signed”操作数应用右移以“拖动”该符号位... - barak manos
显示剩余4条评论
2个回答

13
根据C99标准N1256(重点标记)中的规定:
6.5.7位移运算符
5、表达式E1 >> E2 的结果是将E1右移E2位。如果E1具有无符号类型或者E1具有带符号类型且非负值,则结果的值是商的整数部分,商为 E1 X 2^E2。如果E1具有带符号类型并且为负值,则结果的值由具体实现定义。

5
为了完整起见,这在C89和C11中是相同的。 - Cornstalks
基本上,如果你想要在位移时插入0,先将其转换为无符号整数,进行位移操作,然后再转换回有符号整数即可。 - Cole Tobin
那么我无法预测有符号数的移位运算符的值? - user2738777
@user2738777,这并不是以平台无关的方式编写的。当你从gcc切换到Visual Studio时,行为可能会有所不同,没有保证。 - R Sahu
正如R Sahu所说,这种方法并不是平台无关的。有些平台可能会在符号位上进行移位(就像你的平台一样),但有些平台可能会在0上进行移位。你永远不知道。 - Cole Tobin

6
在C语言中,对负数进行右移操作的行为是由实现定义的。
对于gcc编译器,在文档中强调会传播符号位:
(4.5整数)一些有符号整数的按位运算的结果(C90 6.3,C99和C11 6.5)
按位运算符作用于包括符号位和值位在内的值的表示形式,其中符号位被认为是最高值位上方的。有符号的“>>”通过符号扩展来处理负数。
在其他实现中,一些小型嵌入式平台不会传播符号位,但大多数实现会传播它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接