C提供按位逻辑运算符和移位运算符。
4个按位逻辑运算符都用于整形数据,包括char。之所以叫作按位运算,是因为这些操作都是针对每一个位进行,不影响它左右两边的位。
一元运算符~把1变为0,把0变为1。
~(10011010) //表达式
(01100101) //结果值
在二进制中,00000010表示2,那么取反的值为11111101,即253,该运算符不会改变变量的值。
如果要把val的值改为~val,可以用下面的语句:
val = ~val;
二元运算符&通过逐位比较两个运算对象,生成一个新值。对于每个位,只有两个运算对象中相应的位都为1时,结果才为1(从真/假方面看,只有当两个位都为真时,结果才为真)。
(10010011) & (00111101) //表达式
(00010001) //结果值
C有一个按位与和赋值结合的运算符: &=。下面两条语句产生的最终结果相同”
val &= 0337;
val = val & 0337;
二元运算符|,通过逐位比较两个运算对象,生成一个新值。对于每个位,如果两个运算对象中相应的位为1,结果就为1(从真/假方面看,如果两个运算对象中相应的一个位为真或两个位都为真,那么结果为真)。
(10010011) | (00111101) //表达式
(10111111) //结果值
//效果相同
val |= 0377;
val = val | 0377;
二元运算符^逐位比较两个运算对象。如果两个运算对象中相应的位一个为1(只有一个1),结果为1(从真/假方面看,如果两个运算对象中相应的一个位为真且不是两个同为1,那么结果为真)。
(10010011) ^(00111101) //表达式
(10101110) //结果值
//效果相同
val ^= 0377;
val = val ^ 0377;
按位与运算符常用于掩码/所谓掩码指的是一些设置位开(1)或关(0)的位组合。例如,假设定义符号常量MASK为2(即,二进制形式为00000010),只有1号位为1,其他位都是0。下面的语句:
flags = flags & MASK;
把flags中除1号位以外的所有位都设置位0,因为使用按位与运算符(&)任何位与0组合都得0。1号位的值不变(如果1号位是1,那么1&1得1;如果1号位是0,那么0&1也得0)。这个过程叫作“使用掩码”,因为掩码中的0隐藏了flags中相应的位。
以上一节的flags和MASK为例。下面的语句:
flags = flags | MASK;
把flags的1号位设置为1,且其他位不变。因为使用 | 运算符,任何位与0组合,结果都为本身;任何位与1组合,结果都为1。
和打开特定的位类似,有时也需要在不影响其他位的情况下关闭指定的位。
flags = flags & ~MASK;
由于MASK除1号位为1以外,其他位全为0,所以~MASK除1号位为0以外,其他位全为1。使用&,任何位与1组合都得本身,所以这条语句保持除1号位以外的其他各位不变。
例如,假设flags是00001111,MASK是10110110.下面的表达式:
flags & ~MASK
//即是:
(00001111) & ~(10110110) //表达式
//其结果为:
(00001001) //结果值
MASK中为1的位在结果中都被设置(清空)为0.flags中与MASK为0 的位相应的位在结果中都未改变。
切换位指的是打开已关闭的位,或关闭已打开的位。可以使用按位异或运算符(^)切换位。
假设b是一个位(1或0),如果b为1,则1^b为0;如果b为0,则1^b为1。另外,无论b为1还是0,0^b均为b。 因此,如果使用 ^ 组合一个值和一个掩码,将切换该值与MASK为1的位相对应的位,该值与MASK为0的位相对应的位不变。
flags = flags ^ MASK;
例如,假设flags是00001111,MASK是10110110。
flags ^ MASK
//即是:
(00001111) ^ (10110110) //表达式
//其结果为:
(10111001) //结果值
例如,检查flags中1号位是否被设置为1?可以这样比较:
if ((flags & MASK) == MASK)
puts("wow!");
必须先覆盖flags中的其他位,只用1号位和MASK比较。
为了避免信息漏过边界,掩码至少要与其覆盖的值宽度相同。
左移运算符(<<)将其左侧运算对象每一位的值向左移动其右侧运算对象指定的位数。左侧运算对象移出左末端位的值丢失,用0填充空出的位置。
(10001010) << 2 //表达式
(00101000) //结果值
该操作产生了一个新的位值,但是不改变其运算对象。例如,假设stonk为1,那么stonk<<2为4,但是stonk本身不变,仍为1.可以使用左移赋值运算符(<<=)来更改变量的值。
右移运算符(>>)将其左侧运算对象每一位的值向右移动其右侧运算对象指定的位数。左侧运算对象移出右末端位的值丢失。对于无符号了类型,用0填充空出的位置;对于有符号类型,其结果取决于机器。
对于无符号的值:
(10001010) >> 2
(00100010)
同左移相同,也可以用(>>=)将其左侧的变量向右移动指定数量的位数。
移位运算符针对2的幂提供快速有效的乘法和除法。
number << n //number乘以2的n次幂
number >> n //如果number为非负,则用number除以2的n次幂