二进制位操作

2018-12-23  本文已影响0人  涉川gw

基础概念

位运算

~ (10101)  //原值
  (01010) //取反结果值

值得注意的是取反运算不改变原变量的值,假如一个变量var,赋值为2(八位二进制中表示为00000010),于是~var的运算结果为(11111101),但是var仍为2,所以如果想使用运算后的结果,需要进行赋值,比如:

newvar=~var;
//或
var =~var;
  10011  //操作数1
 &10101 //操作数2
  10001 //结果
 1011 //操作数1
| 1101 //操作数2
  1111 //结果
  10101  //操作数1
^ 11011 // 操作数2
  01110 //结果

位操作的用法

    00000010
&   00001011
    00000010

可以看到,flag除了位1外,其他都被置0了,可以看出掩码的一个作用就是保留掩码为1 的位所对应操作数的位为1,其他位清零。

flag=flag & ~MASK
或者
flag&= ~MASK

同样,MASK保存着需要置0的位,对MASK取反就得到了一个除了待置0位为0,其他位均为1的二进制数:11111101,
然后与操作数进行与操作,就能将待置0位变成0.

  00000010
^ 10000101
  10000111
移位运算
1000 0101 //原码,原码就是一个数的二进制表示,
          //例如这个数是-5的八位二进制表示,高位的1表示是负数
1111 1010 //反码,反码就是一个二进制数的原码,除符号位以外,其余
         // 位取反
1111 1011 //补码,补码就是在反码的基础上加1

所以,对于负数的左移,需要先求出补码,然后用补码来左移,然后再求回原码,就得出了负数左移的结果,例如:上面的-5的补码为1111 1011 ,左移一位后得1111 0110,求这个的原码得:1000 1010 ,即为-10。

实战例子

在读android或java等的源码的时候,我们会看到大量的位运算操作,一开始我是一脸懵逼的,搞不清楚这是什么操作,也不懂为什么要这样操作,看到多了觉得大神都这么玩,肯定是有好处的(位操作会快很多),所以也就决定研究一下其中的原理,接下来就上面所记录的知识来写一个“源码”级别的demo,开整:
test.java

int BYTE_MASK=0xff;
long color=0x002a162f;
int blue,green,red;
red=color & BYTE_MASK;
green=(color >> 8) & BYTE_MASK;
blue =(color >> 16) & BYTE_MASK;
log.d("red="+red+" green="+green+" blue="+blue);

上面这个例子中,color存放的是一个颜色的十六进制值,这个颜色分为三原色,红绿蓝,最低位字节存放红色分量,上一个字节存放绿色分量,第三个字节放蓝色分量,BYTE_MASK作为掩码,上面有介绍过,掩码可以将自身标志位以外的位清除,所以只要用掩码和操作数进行&操作,就能提取出掩码位的数据,上面red=color & BYTE_MASK;就是将color的最后一个字节提取出来,赋值给red,然后因为绿色和蓝色分量不在最后一个字节,所以要用掩码提取,只能先进行移位操作,将对应的颜色分量移位到最后一个字节,然后进行掩码提取数值,最终将三原色分离出来。

总结

位操作不仅能装逼,还能很好的提高程序的性能,是我们进阶中高级码农的必备技能啊,在这记录下,以备岁月摧残记性。

上一篇 下一篇

猜你喜欢

热点阅读