C按位操作符

C提供按位逻辑运算符和移位运算符。

1、按位逻辑运算符

4个按位逻辑运算符都用于整形数据,包括char。之所以叫作按位运算,是因为这些操作都是针对每一个位进行,不影响它左右两边的位。

1.1 二进制反码或按位取反:~

一元运算符~把1变为0,把0变为1。

~(10011010)    //表达式
(01100101)    //结果值

在二进制中,00000010表示2,那么取反的值为11111101,即253,该运算符不会改变变量的值。

如果要把val的值改为~val,可以用下面的语句:

val = ~val;

1.2 按位与:&

二元运算符&通过逐位比较两个运算对象,生成一个新值。对于每个位,只有两个运算对象中相应的位都为1时,结果才为1(从真/假方面看,只有当两个位都为真时,结果才为真)。

(10010011) & (00111101)    //表达式
(00010001)        //结果值

C有一个按位与和赋值结合的运算符: &=。下面两条语句产生的最终结果相同”

val &= 0337;
val = val & 0337;

1.3 按位或:|

二元运算符|,通过逐位比较两个运算对象,生成一个新值。对于每个位,如果两个运算对象中相应的位为1,结果就为1(从真/假方面看,如果两个运算对象中相应的一个位为真或两个位都为真,那么结果为真)。

(10010011) | (00111101)    //表达式
(10111111)                 //结果值
//效果相同
val |= 0377;
val = val | 0377;

1.4 按位异或:^

二元运算符^逐位比较两个运算对象。如果两个运算对象中相应的位一个为1(只有一个1),结果为1(从真/假方面看,如果两个运算对象中相应的一个位为真且不是两个同为1,那么结果为真)。

(10010011) ^(00111101)    //表达式
(10101110)                //结果值
//效果相同
val ^= 0377;
val = val ^ 0377;

2、用法

2.1 掩码(&)

按位与运算符常用于掩码/所谓掩码指的是一些设置位开(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中相应的位。

2.2 打开位(设置位)(|)

以上一节的flags和MASK为例。下面的语句:

flags = flags | MASK;

把flags的1号位设置为1,且其他位不变。因为使用 | 运算符,任何位与0组合,结果都为本身;任何位与1组合,结果都为1。

2.3 关闭位(清空位)(& ~)

和打开特定的位类似,有时也需要在不影响其他位的情况下关闭指定的位。

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 的位相应的位在结果中都未改变。

2.4 切换位(^)

切换位指的是打开已关闭的位,或关闭已打开的位。可以使用按位异或运算符(^)切换位。

假设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)                 //结果值

2.5 检查位的值

例如,检查flags中1号位是否被设置为1?可以这样比较:

if ((flags & MASK) == MASK)
    puts("wow!");

必须先覆盖flags中的其他位,只用1号位和MASK比较。

为了避免信息漏过边界,掩码至少要与其覆盖的值宽度相同。

3、移位运算符

3.1 左移:<<

左移运算符(<<)将其左侧运算对象每一位的值向左移动其右侧运算对象指定的位数。左侧运算对象移出左末端位的值丢失,用0填充空出的位置。

(10001010) << 2        //表达式
(00101000)             //结果值

该操作产生了一个新的位值,但是不改变其运算对象。例如,假设stonk为1,那么stonk<<2为4,但是stonk本身不变,仍为1.可以使用左移赋值运算符(<<=)来更改变量的值。

3.2 右移:>>

右移运算符(>>)将其左侧运算对象每一位的值向右移动其右侧运算对象指定的位数。左侧运算对象移出右末端位的值丢失。对于无符号了类型,用0填充空出的位置;对于有符号类型,其结果取决于机器。

对于无符号的值:

(10001010) >> 2
(00100010)

同左移相同,也可以用(>>=)将其左侧的变量向右移动指定数量的位数。

移位运算符针对2的幂提供快速有效的乘法和除法。

number << n //number乘以2的n次幂
number >> n //如果number为非负,则用number除以2的n次幂

你可能感兴趣的:(C语言,c语言)