彻底理解位运算——与(&)、非(~)、或(|)、异或(^)

目录

与&:

案例如下:

规律如下:

实战案例:

或 |:

案例如下:

规律如下:

实战案例:

异或 ^:

案例如下:

规律如下:

实战案例:

非~:

总结:


与&:

2个二进制进行&操作,只有当2个的数值都为1时,结果才是1。其他均返回0;

案例如下:

15  & 5 = 5
将15和5的二进制分别展示出来

 

由于只有当2个二进制都为1时,结果才为1,其他均为0,所以结果由下图所示。

 

规律如下:

"二进制截断",为何说是二进制截断呢,我们用上面的例子来说,15的二进制低4位都是1,而5的二进制是0101。因为&操作必须都为1结果才是1,所以我们是不是可以理解成5把15的其他位的1给截断成0了呢?那再举个例子,0xFFFF = 65535 = 1111 1111 1111 1111,我们用0x1 = 1 = 0000 0000 0000 0001来进行一个&操作。那么结果是1,也就是把0xFFFF的高31位全部置为0,所以就是用0x1把0xFFFF的高31位都截断为0。

实战案例:

  1. 所以在有些偏底层的操作时,为了空间和时间效率,都是用bit位来做标识位代表一些状态,或者表示地址空间。所以当一个32比特位的值可能其中包含了地址空间,已经很多状态标识位。当我们需要把其中某个状态位置为0的时候,我们就可以通过&的操作。假如把第高17位置为0,我们就可以使用1111 1111 1111 1111 0111 1111 1111 1111 & 源操作数,就可以截断第高17位。
  2. 取余的操作:还记得笔者刚入门程序员的时候,就会做题目来练习,比如遍历1-100,偶数输出什么,奇数输出什么的。其实也就是%2取余的一个操作。那么其实也可以使用&与操作来完成。我们找到其中的规律,当一个十进制转换成二进制后,二进制最后一位为0,要么是0要么就是2的倍数(偶数),反而如果最后一位为1,那么要么是1,要么就是奇数(当然1也是奇数)。所以规律就是:源操作数 & 1,如果为0那么就是偶数,如果为1就是奇数。并且任何数取余都可以,当我们需要取1024的余数时,我们只需要用源操作数 & 1024-1,结果就是1024的余数了,因为1023再加1就是全部进位,所以1023是1024位的所有低位为1,所以通过&操作就可以得出1024的余数(这里笔者,描述能力有点欠佳,大家可以自行测试论证)

或 |:

2个二进制进行 | 操作,只需要2个二进制存在一个1,结果就是1(2个二进制都为1也是1),很好理解,除了2个二进制都为0,其他结果都是1。

案例如下:

10 | 5 = 15

将10和5的二进制分别展示出来

由于只需要2个二进制中存在一个1结果就为1,所以 | 操作后由下图所示。

规律如下:

"二进制组合",这个很好理解,不做多的解释,也就是把2组二进制对齐后组合起来....

实战案例:

  1. 上面描述的&操作中的第一个实战案例,说的是怎么用&操作把某个bit位的状态位置为0,那么 | 操作是不是可以把某个比特位置为1呢?毕竟是二进制组合,我们只需要写一组二进制与源操作数对齐后,把状态位需要置为1的哪一位写成1,就大功告成。
  2. 第2个案例也是基于第一个案例,我们看到Linux2.6内核的源码中(这是fork和clone时,父子进程的配置项,不知道也不影响此案例)。我们在项目中,是不是有很多配置项呢,那么最后如何优雅又高效的管理这些这些配置项呢?没错每个配置对应一组二进制(虽然图中是16进制,进制转换一下就行了么),最后通过 | 操作将这些配置组合起来。判断配置项的时候是不是就可以使用&操作呢(为0就代表没开启某些配置项,点到为止,不过细讲)?

 

异或 ^:

2个二进制 ^异或操作,只要2个二进制相同结果就为0,不相同就为1。(注意这里是判断是否相同,并没有判断是不是又1)

案例如下:

 

规律如下:

"二进制无进位加法",也很好理解,^异或操作是相同为0,不相同为1。而相同的结果只有为11或者00,而11的结果为0,11所以可以理解为二进制做了加法但是没有进位(相加后为0,但是要向高位进1的,但是不进位),而00相加还是为0。而对于不相同的只有10或者01。而01或者10异或操作结果为1,而他们相加也是为1。所以就可以说明异或就是二进制无进位加法。

实战案例:

  1. 扰动函数(可以自行百度理解)
  2. 两数交换,使用^异或操作,可以不借用临时变量。
    a = 0011 0010;
    b = 0010 1010;
    
    a = a ^ b;   // 运算后a = 0001 1000   b = 0010 1010
    b = b ^ a;   // 运算后b = 0011 0010 , a = 0001 1000
    a = a ^ b;   // 运算后a = 0010 1010 , b = 0011 0010
  3. 2个相等的数进行^异或操作结果是不是为0,所以可以用来判断是否相等。

非~:

把整个二进制全部取反,0变成1,1变成0。这个太简单了,就不画图理解了。

总结:

找到规律后,就能做到一眼看出答案。

最后,如果本帖对您有一定的帮助,希望能点赞+关注+收藏!您的支持是给我最大的动力,后续会一直更新各种框架的使用和框架的源码解读~!

  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员李哈

创作不易,希望能给与支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值