C语言位运算符

位运算虽然考试比较少,但与硬件相关的接触比较多。

对于更多紧凑的数据,C 程序可以用独立的位或多个组合在一起的位来存储信息。文件访问许可就是一个常见的应用案例。位运算符允许对一个字节或更大的数据单位中独立的位做处理:可以清除、设定,或者倒置任何位或多个位。也可以将一个整数的位模式(bit pattern)向右或向左移动。 整数类型的位模式由一队按位置从右到左编号的位组成,位置编号从 0 开始,这是最低有效位(least significant bit)。例如,考虑字符值'*',它的 ASCII 编码为 42,相当于二进制的 101010: 位模式 0 0 1 0 1 0 1 0 位位置 7 6 5 4 3 2 1 0 在本例中,值 101010 被表示成一个 8 位的字节内容,因此前面多两个 0。

布尔位运算符

表 1 中列举的运算符可以对操作数的每个位进行布尔运算。这种二元运算符把两个不同操作数内相同位置的位关联起来。被设定的位(也就是值为 1 的位)被解释为 true,被清除的位(也就是值为 0 的位)被解释为 false。 除布尔运算符 AND、OR 和 NOT 以外,也有位异或运算符(exclusive-OR,XOR)。这些都在表 1 进行了列举。

运算符

意义

示例

对于每个位位置的结果(1=设定,0=清除)

&

位 AND

x&y

如果 x 和 y 都为 1,则得到 1;如果 x 或 y 任何一个为 0,或都为0,则得到 0

|

位 OR

x|y

如果 x 或 y 为 1,或都为 1,则得到 1;如果 x 和 y 都为 0,则得到 0

^

位 XOR

x^y

如果 x 或 y 的值不同,则得到 1;如果两个值相同,则得到 0

~

位 NOT(I的补码)

~x

如果 x 为 0,则得到 1,如果 x 是 1,则得到 0

位运算符的操作数必须是整数类型,并且遵循寻常算术转换(usualarithmetic conversion)。转换后获得的操作数通用类型就是整个计算结果的类型。表 2 展示了这些运算符的效果。

表达式(或声明)

位模式

int a=6;

0···00110

int b=11;

0···01011

a&b

0···00010

a|b

0···01111

a^b

0···01101

~a

1···11001

可以将一个整数 a 的特定位清除,做法是将整数 a 和另一个整数进行位 AND 运算,其中,另一个整数在需要清除的位为 0,其他位则为 1,并位 AND 运算,其中,另一个整数在需要清除的位为 0,其他位则为 1,并将 AND 运算的结果赋值给整数 a。 该另一个整数,即位 AND 运算的第二个操作数,被设定为 1 的位置(称为位掩码),这些位置经过位 AND 运算,不会改变第一个操作数对应位置的值。例如,一个整数与一个位掩码 0xFF 进行位 AND 运算后,将保留最低位置的 8 个位,而会清除其他所有位的值:

a &= OxFF;            // 相当于:a = a & OxFF;

在该示例中,复合赋值运算符 &= 也会执行 & 运算。复合赋值运算符与其他二元位运算符具有类似的执行方式,这里不再赘述。 位运算符也可以用来生成位掩码,以供以后的位运算使用。例如,在位模式 0x20 中,只有位5被设定。因此表达式 ~0x20 会生成一个只有位 5 没有被设定的位掩码:

a &= ~0x20;             // 清除a中的位5

位掩码 ~0x20 比 0xFFFFFFDF 更受欢迎,因为它的可移植性更好:结果不会受到机器字大小的影响(同时也更方便人阅读)。 也可以使用运算符 |(OR)和 ^(XOR)来设定或清除特定位,下面是一个示例:

int mask = OxC;a |= mask;              // 设定a的位2和位3a ^= mask;              // 求反a的位2和位3

第二个转换使用相同的位掩码,它会将第一次转换的结果再反转一次。换句话说,b^mask^mask 会得到原来 b 的值。这个操作可以用于交换两个整数的值,而不需要使用第三个临时变量:

a ^= b;                  // 等效于 a = a ^ b;b ^= a;                 // 将a原来的值赋值给ba ^= b;                 // 将b原来的值赋值给a

本例中的前两个表达式等同于 b=b^(a^b)或 b=(a^b)^b。其结果等同于 b=a,副作用是 a 的值也被修改了,其修改后的值为 a^b。在这时,第三个表达式具有如下副作用 a=(a^b)^a 或 a=b(使用 a 和 b 的原始值)。

移位运算符

移位运算符将左操作数的位模式移动数个位置,至于移动几个位置,由右操作数指定。它们如表 3 列举。

运算符

意义

示例

结果

<<

向左移位

x<<y

x 的每个位向左移动 y 个位

>>

向右移位

x>>y

x 的每个位向右移动 y 个位

移位运算符的操作数必须是整数。在实际移位操作之前,两个操作数都要进行整数提升(promotion)。右边操作数不可以为负值,并且必须少于左边操作数在整数提升之后的位长。如果不符合这些条件,程序运行结果将无法确定。 移位运算结果的类型等于左操作数在整数提升后的类型。下面示例的移位表达式具有 unsigned long 类型。

unsigned long n = 0xB,     // 位模式:0 ... 0 0 0 1 0 1 1result = 0;result = n << 2;          //              0 ... 0 1 0 1 1 0 0result = n >> 2;          //              0 ... 0 0 0 0 0 1 0

在向左移位运算时,右边多出来的位用 0 来填充。移动超出左边边界的位则直接抛弃。向左移动 y 个位置,就等同于将左操作数乘以 2^{y}:如果左操作数 x 是无符号类型,那么表达式 x<<y 的结果等于表达式 x×2^{y} 的值。因此,在前面的例子,n<<2 的值为 n×4,也就是 44。 在向右位移运算时,如果左操作数是无符号类型,或者左操作数是带符号类型但为非负值,则左边多出来的位用 0 来填充。在这种情况下,表达式 x>>y 的结果等效于表达式 x/2^{y} 的值。如果左操作数是负值,那么由编译器决定用于填充至左边多出来的位的内容,可能是 0,也可能是符号位。

// 函数setBit()// 设定掩码m中p位置的位。// 使用定义在limits.h中的CHAR_BIT,存储一个字节内的位的数目。// 返回值:完成位设定的新掩码,其中p位置已设定好//              如果p不是有效的位置,则返回原始掩码。
unsigned int setBit( unsigned int mask, unsigned int p ){if ( p >= CHAR_BIT * sizeof(int) )return mask;elsereturn mask | (1<<p);}

移位运算符的优先级比算术运算符的优先级更低,但相对于比较运算符以及其他的位操作运算符,具有更高的优先级。上例表达式 mask|(1<<p)中的括号必要性不大,主要是让程序代码更容易阅读。


本文分享自微信公众号 - 计算机二级C语言(gh_044a0595bf44),作者:点此关注☞

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C语言入门笔记2

    我们上小学的时候都学过各种运算,如:加法运算、乘法运算、混合运算等,而运算就要用到运算符,如:+、-、×、÷等等。

    用户6755376
  • 习题:表达式

    首先,这两个结果肯定是不一样的。第一种情况,a最终的值是6;第二种加了括号,a最终的值是3。

    用户6755376
  • 全国计算机二级C知识点总结1

    2.C语言程序源文件名的后缀是.c;经过编译后,生成的文件的后缀是.obj;经过连接后,生成文件的后缀是.exe。

    用户6755376
  • 【Go 语言社区】Go语言运算符

    运算符是一个符号,告诉编译器执行特定的数学或逻辑操作。 Go语言有丰富的内置运算符和运算符提供的以下几种类型: 算术运算符 关系运算符 逻辑运算符 位运算符 赋...

    李海彬
  • Go语言运算符

    运算符是一个符号,告诉编译器执行特定的数学或逻辑操作。 Go语言有丰富的内置运算符和运算符提供的以下几种类型: 算术运算符 关系运算符 逻辑运算符 位运算符 赋...

    李海彬
  • Python3 运算符

    以上代码输出: a 和 b 指向同一个存储对象,有相同的标识 a 和 b 指向同一个存储对象,有相同的标识 a 和 b 没指向同一个存储对象,没有相同的标识 a...

    py3study
  • 微课|玩转Python轻松过二级(2.2.1节):算术运算符

    Python小屋屋主
  • Golang语言--运算符

    运算符是一个符号,告诉编译器执行特定的数学或逻辑操作。 Go语言有丰富的内置运算符和运算符提供的以下几种类型: 算术运算符 关系运算符 逻辑运算符 位运算符 赋...

    李海彬
  • python运算符

    & 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0

    老雷PHP全栈开发
  • 【程序源代码】《零基础学编程-python》第2期20200622

    什么是运算符?运算符用于执行程序代码运算,会针对一个以上操作数项目来进行运算。例如:2+3,其操作数是2和3,而运算符则是“+”。在vb2005中运算符大致可以...

    程序源代码

扫码关注云+社区

领取腾讯云代金券