
5.7 位运算符
位运算符(bitwise operator)能够依照常用的方式操作二进制值。按位与(也叫按位和,AND,&)、按位或(OR,|)以及按位异或(XOR,^)运算符都会逐位比较两个操作数,以计算出结果。移位(也叫按位移动)运算符会把第一个操作数的所有二进制位向左或向右移动一段距离(这段距离由第二个操作数确定)。按位取反(也叫按位求补,bitwise complement)运算符会翻转操作数的每个二进制位以确定计算结果。
我们可以拿8个、16个或32个二进制位构造一个位字段(bit field,又称位域),以便用其中的每个二进制位来充当开关(switch)或标志(flag),从而决定程序中的某项功能或特性是处于停用(off,0)状态,还是处于启用(on,1)状态。用位字段中的二进制位来启用或停用某项特性,主要的缺点在于,这些二进制位的含义只有读到了源代码之后才能明白,于是这就要求我们必须提供源代码,而且要在里面详细注明这些二进制位的意思。
目前,位运算的意义已经不像原来那样大了,因为现在的内存与CPU寄存器资源都比较充裕,而且价格比较低,另外,在目前这种情况下执行位运算,开销反而会比较大。有时我们确实需要在程序里面使用这种运算,但这样的场合并不多见。
C语言一共有6个位运算符:
□&:按位与(也叫按位和)。如果两个操作数对应位置上的两个二进制位都是1,那么在表示运算结果的数里,这个二进制位也是1。
□|:按位或。如果两个操作数对应位置上的两个二进制位至少有一个为1,那么在表示运算结果的数里,这个二进制位也是1。
□^:按位异或。如果两个操作数对应位置上的两个二进制位,其中一个是1而另一个不是,那么在表示运算结果的数里,这个二进制位是1。
□<<:按位左移。把第一个操作数的每个二进制位都向左(也就是朝着权重较高的方向)移动一段距离(这段距离由第二个操作数确定)。例如value<<1就相当于value*2。0010这个二进制值,左移一位之后就变成了0100。
□>>:按位右移。把第一个操作数的每个二进制位都向右(也就是朝着权重较低的方向)移动一段距离(这段距离由第二个操作数确定)。例如value>>1就相当于value/2。0010这个二进制值,右移一位之后就变成了0001。
□~:按位取反(也叫按位求补、按位非、按位否)。把操作数的每个二进制位翻转(也就是把1变成0,把0变成1),以确定计算结果。
下面这段范例代码演示了如何用位运算符来操作位字段里面的标志:

除了用位字段里面的二进制位来表示各种开关,我们还可以考虑定义自己的枚举(enumeration)类型,或采用更为明确的数据结构(例如哈希表),这两种方案通常比位字段更好。