当前位置:编程学习 > C/C++ >>

C语言中的移位运算

我曾经写过一个显示int类型数据二进制表示(补码)的小程序,代码如下:
  #include <limits.h> #include <stdio.h>
  int main(void) { int i = 0;int value = -128; // 0xffffff80 int shift = INT_MIN; // 0x80000000
  printf("The decimal value is: %d\n\n", value);
  printf("*      *       *       *\n");// print marks
  for (i = 0; i < 32; ++i) { if (shift & value) { printf("1");} else { printf("0");}
  shift = shift >> 1; // right shift 1 bit } // print bits
  return 0;}预期的输出如下:
  The decimal value is: -128
  *       *       *       * 11111111111111111111111110000000然而实际的输出如下:
  The decimal value is: -128
  *       *       *       * 11111111111111111111111111111111追踪变量shift的值,发现其最高位(MSB)始终为1,我恍然大悟:这货是算术右移,也就是说会保留符号位。于是,将shift改为(unsigned int)类型,果然解决了这个bug.说明,对于无符号数,进行的是逻辑右移,在移走的位上填0.
  下面我们自然会联想到,是不是无符号数的左移为逻辑左移,而有符号数的左移为算术左移(即保留符号位)呢?答案是非也,事实上逻辑左移与算术左移是相同的,都不会保留符号位。
  右移运算的结果是不会超出表示范围的。对于有符号数,右移一位后符号位空出,则必须保留原符号位的值;对于无符号数,没有符号位,自然采取逻辑右移。
  左移运算则不同,它是有可能超出表示范围的,也就是溢出。对于MSB位为0、MSB-1位为1的有符号正数,及MSB位为1、MSB-1位为0的有符号负数,左移必将益出(以int类型为例,其表示范围是-2^31~2^31-1,对于大于等于2^30和小于等于-2^30-1的值左移1位,也就是乘以2,必然超出了表示范围),且只有在这些情况下符号位才发生变化。既然已经溢出了,保留原符号位还有什么意义?
  综上,C语言中可以进行位运算的char/short/int/long (int)/long long (int)类型是有符号的,加上unsigned前缀则是无符号的,两者在右移运算上是有区别的。

补充:软件开发 , C语言 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,