C语言位运算符的五种用法:打开位,关闭位,切换位,检查位和位移符


C语言位运算符的五种用法:打开位,关闭位,切换位,检查位和位移符


1 打开位(设置位)

有时,需要打开一个值中的特定位,同时保持其他位不变。例如,一台IBM PC通过向端口发送值来控制硬件。例如,为了打开内置扬声器,必须打开1号位,同时保持其他位不变。这种情况可以使用按位或运算符(|)。 以上一节的flags和MASK(只有1号位为1)为例。下面的语句:

flags = flags | MASK;

把flags的1号位设置为1,且其他位不变。因为使用|运算符,任何位与0组合,结果都为本身;任何位与1组合,结果都为1。例如,假设flags是00001111,MASK是10110110。下面的表达式:

flags | MASK

变成:

(00001111) | (10110110)  // expression

结果为:

(10111111)               // resulting value

MASK中为1的位,flags与其对应的位也为1。MASK中为0的位,flags与其对应的位不变。用|=运算符可以简化上面的代码,如下所示:

flags |= MASK;

同样,这种方法根据MASK中为1的位,把flags中对应的位设置为1,其他位不变。

2 关闭位(清空位)

和打开特定的位类似,有时也需要在不影响其他位的情况下关闭指定的位。假设要关闭变量flags中的1号位。同样,MASK只有1号位为1(即,打开)。可以这样做:

flags = flags & ~MASK;

由于MASK除1号位为1以外,其他位全为0,所以~MASK除1号位为0以外,其他位全为1。使用&,任何位与1组合都得本身,所以这条语句保持除1号位以外的其他各位不变。另外,使用&,任何位与0组合都得0。所以无论1号位的初始值是什么,都将其设置为0。例如,假设flags是00001111,MASK是10110110。下面的表达式:

flags & ~MASK

即是:

(00001111) &^ (10110110)  // expression

其结果为:

(00001001)               // resulting value

MASK中为1的位在结果中都被设置(清空)为0。flags中与MASK为0的位相应的位在结果中都未改变。可以使用下面的简化形式:

flags &= ~MASK;

3 切换位

切换位指的是打开已关闭的位,或关闭已打开的位。可以使用按位异或运算符(^)切换位。也就是说,假设b是一个位(1或0),如果b为1,则1b为0;如果b为0,则1b为1。另外,无论b为1还是0,0b均为b。因此,如果使用组合一个值和一个掩码,将切换该值与MASK为1的位相对应的位,该值与MASK为0的位相对应的位不变。要切换flags中的1号位,可以使用下面两种方法:

flags = flags ^ MASK;
flags ^= MASK;

例如,假设flags是00001111,MASK是10110110。表达式:

flags ^ MASK

即是:

(00001111) ^ (10110110)  // expression

其结果为:

(10111001)               // resulting value

flags中与MASK为1的位相对应的位都被切换了,MASK为0的位相对应的位不变。

4 检查位

的值前面介绍了如何改变位的值。有时,需要检查某位的值。例如,flags中1号位是否被设置为1?不能这样直接比较flags和MASK:

if (flags == MASK)
  puts("Wow!");    /* doesn't work right */

这样做即使flags的1号位为1,其他位的值会导致比较结果为假。因此,必须覆盖flags中的其他位,只用1号位和MASK比较:

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

由于按位运算符的优先级比==低,所以必须在flags & MASK周围加上圆括号。为了避免信息漏过边界,掩码至少要与其覆盖的值宽度相同。

5 移位运算符

下面介绍C的移位运算符。移位运算符向左或向右移动位。同样,我们在示例中仍然使用二进制数,有助于读者理解其工作原理。

1.左移:<<左移

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

(10001010) << 2  // expression
(00101000)       // resulting value

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

int stonk = 1;
int onkoo;
onkoo = stonk << 2;   /* assigns 4 to onkoo */
stonk <<= 2;          /* changes stonk to 4 */

2.右移:>>

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

(10001010) >> 2  // expression, signed value
(00100010)       // resulting value, some systems
(10001010) >> 2  // expression, signed value
(11100010)       // resulting value, other systems

下面是无符号值的例子:

(10001010) >> 2  // expression, unsigned value
(00100010)       // resulting value, all system

每个位向右移动两个位置,空出的位用0填充。右移赋值运算符(>>=)将其左侧的变量向右移动指定数量的位数。如下所示:

int sweet = 16;
int ooosw;

ooosw = sweet >> 3;  // ooosw = 2, sweet still 16
sweet >>=3;          // sweet changed to 2

3.用法:移位运算符

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


这些移位运算符类似于在十进制中移动小数点来乘以或除以10。移位运算符还可用于从较大单元中提取一些位。例如,假设用一个unsigned long类型的值表示颜色值,低阶位字节存储红色的强度,下一个字节存储绿色的强度,第3个字节存储蓝色的强度。随后你希望把每种颜色的强度分别存储在3个不同的unsigned char类型的变量中。那么,可以使用下面的语句:

#define BYTE_MASK 0xff
unsigned long color = 0x002a162f;
unsigned char blue, green, red;
red = color & BYTE_MASK;
green = (color >> 8) & BYTE_MASK;
blue = (color >> 16) & BYTE_MASK;

以上代码中,使用右移运算符将8位颜色值移动至低阶字节,然后使用掩码技术把低阶字节赋给指定的变量。

展开阅读全文

页面更新:2024-03-16

标签:空出   圆括号   左端   低阶   组合   位移   表达式   位数   变量   字节   语句   强度   符号   对象   位置

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top