简述位操作符

简述位操作符

额,似乎这不应该由我来写,不过既然已经开始写了,那就把它完成好了~

  大家都知道,数据在计算机中是以二进制的方式进行储存,而二进制只用0和1来表示数,如果对应成真值,则是True或False 。0和1往往给人一种简谐美的感觉,正如莱布尼茨所说,他从0和1中看到了宇宙的创生。额,似乎跑题了,拉回来~

  而位操作符则是用来通过对存储的二进制数操作的一些符号。

  PS:如非特殊声明,以下均是指整数而非浮点数

1.位操作符

  常见的位操作符有如下:

操作符


作用


用法


真值表


~
按位非
~exp
~0 -> 1
~1->0

&
按位与
exp1 & exp2
exp均为1才为1
|
按位或
exp1 | exp2
exp中有一个为1则为1
^
按位异或
exp1 ^ exp2
1^0才为1


类似+=等复合符号,除了~之外,均有=&、=|、^=复合符号。

  而且,位操作符中存在“移动操作符”:<<和>>

  exp<<n表示把exp中的位往左移动n位,移出边界的则被丢弃,从右边开始用0补空位。
  exp>>n表示把exp中的位往右移动n位,移出边界的则被丢弃,从左边开始用符号位补空位。

  PS:很多书上都写着>>也是从左边开始用0补空位,但是经过我的Lieo的实际测试,实际上是用符号位补充。
  PPS:符号位将在后面介绍~

2.实例

  春节到了,酒店也开始忙开了,很多人为了和家人一起吃年夜饭,都会去酒店预定房间。每个房间有两个状态:被预订和尚未被预订。

  酒店经理KC每天都要审查客房的预订情况,做好分析。但是普通的记录方法会浪费很多时间和资源,于是他决定用一个整数和位操作来简化工作。

   这里我们假设一个无符号的16位整数(unsigned short)n,每一位表示酒店的一个房间,如果房间被预订,那么这位上的数字就是1,否则是0。
  开始时,所有的房间都是尚未被预订,所以状态均为0。相应的,我们只需要简单的初始化n即可:
引用:
unsigned short n = 0;
后来,KC接到电话,3号客房被预定,于是,我们需要翻转第三位:
引用:
short a = 0;
  
a |= (1 << 2);
  
//      1:  0000 0000 0000 0001      
  // 1 << 2:  0000 0000 0000 0100
这样,第三位便从0被翻转成了1

  陆续的,7号和13号客房也被人预订。类似的我们也要翻转第7位和第13位:
引用:
short a = 0;
  
a |= (1 << 2);
  
a |= (1 << 6);
  
a |= (1 << 12);
后来,由于特殊原因,7号房间的客人取消了预订,于是我们有需要把第7位翻转回去
引用:
  short a = 0;
  
a |= (1 << 2);
  
a |= (1 << 6);
  
a |= (1 << 12);
  
a ^= (1 << 6);
由于位操作比较底层,容易出错,所以通常会把它弄成宏或者封装起来使用。在标准的C++库中,就有一个Bitset类。不过我们这次不在此讨论,有兴趣的可以自己去翻翻参考文档~

3.原码、反码和补码

  我们在上面的例子中,使用的是无符号整数,最高位符号位被舍弃。下面我们就来看下有符号整数在内存中的二进制形式。

  对于有符号整数来说,比如16位的有符号整数short,他的最高位被用来标示数字的符号,0位正数,1为负数,因此,存储位只有7位,所以他只能表示-32767~32768.

  那么什么是原码呢?通常来说,正数的原码就是其本身,而负数的原码除符号位之外,其余位和正数原码相同。

  反码则是把负数除了符号位之外的其他位,按位非处理,如果把负数反码加上1,则得到的是补码。而有符号整数通常都是以补码的形式进行保存。
  CAUTION:正数的反码、补码都是其本身

  举个例子来加深印象:

有符号整数


原码


反码


补码


56


0000 0000 0011 1000


0000 0000 0011 1000


0000 0000 0011 1000


-56


1000 0000 0011 1000


1111 1111 1100 0111


1111 1111 1100 1000




理解完原码、反码和补码之后,我们在好回头看看前面的位操作。

  当我们使用>>移动时,左边空出来的都用符号位去填充,所以导致了-1>>n出来的都是-1的情况。而对一个有符号整数进行~操作时,也极易出现问题,因为符号位也被翻转了。

------------------------------------------EOF---------------------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值