位运算之左移右移运算之详解

转自:http://www.cnblogs.com/yyangblog/archive/2011/01/14/1935656.html


代码
 
 #include "stdio.h"
 
 char leftshift(char i, int n)
 {
     if(n < 0)
         return -1;
     return i<<n;
 }
 
 char rightshift(char i, int n)
 {
     if(n < 0)
         return -1;
     return i>>n;
 }
 
 int main()
 {
     //leftshift
     char a1 = 127;
     char a2 = -1;
 
     for(int i = 1; i <= 8; i++)
         printf("%d<<%d = %d;\n", a1, i, leftshift(a1,i));
 
     for(i = 1; i <= 8; i++)
         printf("%d<<%d = %d;\n", a2, i, leftshift(a2,i));
 
     //rightshift
     a1 = 127;
     a2 = -128;
 
     for(i = 1; i <= 8; i++)
         printf("%d>>%d = %d;\n", a1, i, rightshift(a1,i));
 
     for(i = 1; i <= 8; i++)
         printf("%d>>%d = %d;\n", a2, i, rightshift(a2,i));
 
     return 0;
 }

结果
 <<1 = -2;
 <<2 = -4;
 <<3 = -8;
 <<4 = -16;
 <<5 = -32;
 <<6 = -64;
 <<7 = -128;
 <<8 = 0;
 
 -1<<1 = -2;
 -1<<2 = -4;
 -1<<3 = -8;
 -1<<4 = -16;
 -1<<5 = -32;
 -1<<6 = -64;
 -1<<7 = -128;
 -1<<8 = 0;
 >>1 = 63;
 >>2 = 31;
 >>3 = 15;
 >>4 = 7;
 >>5 = 3;
 >>6 = 1;
 >>7 = 0;
 >>8 = 0;
 
 -128>>1 = -64;
 -128>>2 = -32;
 -128>>3 = -16;
 -128>>4 = -8;
 -128>>5 = -4;
 -128>>6 = -2;
 -128>>7 = -1;
 -128>>8 = -1;

左移操作(<<)
 规则:
 右边空出的位用0填补
 高位左移溢出则舍弃该高位。
 计算机中常用补码表示数据:
 数据 127,补码和原码一样:0111 1111。
 左移一位: 1111 1110   -> 这个补码对应的原码为:1000 0010  对应十进制:-2
 左移二位: 1111 1100   -> 这个补码对应的原码为:1000 0100  对应十进制:-4
 左移三位: 1111 1000   -> 这个补码对应的原码为:1000 1000  对应十进制:-8
 左移四位: 1111 0000   -> 这个补码对应的原码为:1001 0000  对应十进制:-16
 左移五位: 1110 0000   -> 这个补码对应的原码为:1010 0000  对应十进制:-32
 左移六位: 1100 0000   -> 这个补码对应的原码为:1100 0000  对应十进制:-64
 左移七位: 1000 0000   -> 这个补码对应的原码为:1000 0000  对应十进制:-128
 左移八位: 0000 0000   -> 这个补码对应的原码为:0000 0000  对应十进制:0
 注:
 原码到补码的计算方式:取反+1,
 补码到原码的计算方式:-1再取反。
 数据-1,它的原码为1000 0001,补码为1111 1111
 左移一位: 1111 1110   -> 这个补码对应的原码为:1000 0010  对应十进制:-2
 左移二位: 1111 1100   -> 这个补码对应的原码为:1000 0100  对应十进制:-4
 左移三位: 1111 1000   -> 这个补码对应的原码为:1000 1000  对应十进制:-8
 左移四位: 1111 0000   -> 这个补码对应的原码为:1001 0000  对应十进制:-16
 左移五位: 1110 0000   -> 这个补码对应的原码为:1010 0000  对应十进制:-32
 左移六位: 1100 0000   -> 这个补码对应的原码为:1100 0000  对应十进制:-64
 左移七位: 1000 0000   -> 这个补码对应的原码为:1000 0000  对应十进制:-128
 左移八位: 0000 0000   -> 这个补码对应的原码为:0000 0000  对应十进制:0
 可以看出127和-1的结果完全一样。移位操作与正负数无关,它只是忠实的将所有位进行移动,补0,舍弃操作。
 右移操作(>>)
 规则:
 左边空出的位用0或者1填补。正数用0填补,负数用1填补。注:不同的环境填补方式可能不同;
 低位右移溢出则舍弃该位。
 1、127的补码:0111 1111
 右移一位: 0011 1111   -> 原码同补码一样  对应十进制:63
 右移二位: 0001 1111   -> 原码同补码一样  对应十进制:31
 右移三位: 0000 1111   -> 原码同补码一样  对应十进制:15
 右移四位: 0000 0111   -> 原码同补码一样  对应十进制:7
 右移五位: 0000 0011   -> 原码同补码一样  对应十进制:3
 右移六位: 0000 0001   -> 原码同补码一样  对应十进制:1
 右移七位: 0000 0000   -> 原码同补码一样  对应十进制:0
 右移八位: 0000 0000   -> 原码同补码一样  对应十进制:0
 2、-128的补码:1000 0000
 右移一位: 1100 0000   -> 这个补码对应的原码为:1100 0000  对应十进制:-64
 右移二位: 1110 0000   -> 这个补码对应的原码为:1010 0000  对应十进制:-32
 右移三位: 1111 0000   -> 这个补码对应的原码为:1001 0000  对应十进制:-16
 右移四位: 1111 1000   -> 这个补码对应的原码为:1000 1000  对应十进制:-8
 右移五位: 1111 1100   -> 这个补码对应的原码为:1000 0100  对应十进制:-4
 右移六位: 1111 1110   -> 这个补码对应的原码为:1000 0010  对应十进制:-2
 右移七位: 1111 1111   -> 这个补码对应的原码为:1000 0001  对应十进制:-1
 右移八位: 1111 1111   -> 这个补码对应的原码为:1000 0001  对应十进制:-1
 常见应用
 左移相当于*2,只是要注意边界问题。如char a = 65; a<<1 按照*2来算为130;但有符号char的取值范围-128~127,已经越界,多超出了3个数值,所以从-128算起的第三个数值-126才是a<<1的正确结果。
 而右移相当于除以2,只是要注意移位比较多的时候结果会趋近去一个非常小的数,如上面结果中的-1,0。
 其它的四种位运算:
 与运算(&)
 1、与0相与可清零
 2、与1相与可保留原值
 或运算(|)
 1、与0相或可保留原值
 2、与1相与可齐设1
 异或运算(^)
 1、与0异或保留原值
 2、与1异或比特值反转
 3、可通过某种算法,使用异或实现交换两个值
 异或运算是有结合律的
 取反(~)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值