6. 位运算符
位运算是指对整数在二进制位级别上进行的运算。
位操作经常用在嵌入式系统和 Linux 内核驱动程序中。
C 语言位运算的运算符有如下 6 种:
& // 按位与运算
| // 按位或运算
^ // 按位异或运算
<< // 左移运算
>> // 右移运算
~ // 按位取反运算
其中 &、|、^、<<、>> 是二元运算符,且左右两个操作数一定是整数。
语法格式如下:
左表达式 二元位运算符 右表达式
~ 是一元运算符
语法格式如下:
~ 表达式
6.1 按位与运算(&)
按位与运算是两个操作数的对应位都为 1 时,该位结果才为 1;否则该位结果为 0。
按位与运算的特点是一个位和 0 与则变为 0 , 和 1 与则不变。
示例
#include <stdio.h>
int main(int argc, char *argv[]) {
short int x = 0x29; // 00000000 00101001
short int y = 0x27; // 00000000 00100111
short int z;
z = x & y;
printf("z: 0x%04x\n", z);
return 0;
}
执行结果如下:
z: 0x0021
运算过程
z = x & y;
x: 00000000 00101001
y: & 00000000 00100111
--- -------- --------
z: 00000000 00100001
6.2 按位或运算(|)
按位或运算是两个操作数的对应位都为 0 时,该位结果才为 0;否则该位结果为 1。
按位或运算的特点是一个位和 1 或则变为 1 ,和 0 或则不变。
示例
#include <stdio.h>
int main(int argc, char *argv[]) {
short int x = 0x29; // 00000000 00101001
short int y = 0x27; // 00000000 00100111
short int z;
z = x | y;
printf("z: 0x%04x\n", z);
return 0;
}
执行结果如下:
z: 0x002f
运算过程
z = x | y;
x: 00000000 00101001
y: | 00000000 00100111
--- -------- --------
z: 00000000 00101111
6.3 按位异或运算(^)
按位异或运算是两个操作数的对应位不相同时,该位结果为 1;相同该位结果为0。
按位异或运算的特点是一个位和 1 异或则翻转(1变 0,0变 1) , 和 0 异或则不变。
示例
#include <stdio.h>
int main(int argc, char *argv[]) {
short int x = 0x29; // 00000000 00101001
short int y = 0x27; // 00000000 00100111
short int z;
z = x ^ y;
printf("z: 0x%04x\n", z);
return 0;
}
执行结果如下:
z: 0x000e
运算过程
z = x ^ y;
x: 00000000 00101001
y: ^ 00000000 00100111
--- -------- --------
z: 00000000 00001110
6.4 左移运算(<<)
左移运算(<<)是将操作数的所有位向左侧移动指定的位数,高位溢出丢掉,低位补 0。
示例
#include <stdio.h>
int main(int argc, char *argv[]) {
short int x = 0x29; // 00000000 00101001
short int z;
z = x << 1;
printf("z: 0x%04x\n", z);
z = x << 2;
printf("z: 0x%04x\n", z);
return 0;
}
执行结果如下:
z: 0x0052
z: 0x00a4
运算过程
z = x << 1;
x: 00000000 00101001
<< 00000000 00000001
--- -------- --------
z: 0 00000000 01010010 <-- 补1个 0
z = x << 2;
x: 00000000 00101001
<< 00000000 00000010
--- -------- --------
z: 00 00000000 10100100 <-- 补2个 0
6.5 右移运算(>>)
右移运算(>>)是将操作数的所有位向右侧移动指定的位数,低位溢出丢掉,对于高位有这两种不同的填补方法:
- 对于无符号数:高位补
0。 - 对于有符号数:高位补符号位(算术右移)。
示例
#include <stdio.h>
int main(int argc, char *argv[]) {
short int x = 0x29; // 00000000 00101001
short int z;
z = x >> 1;
printf("z: 0x%04x\n", z);
z = x >> 2;
printf("z: 0x%04x\n", z);
return 0;
}
执行结果如下:
z: 0x0014
z: 0x000a
运算过程
z = x >> 1;
x: 00000000 00101001
>> 00000000 00000001
--- -------- --------
z: 00000000 00010100 1(溢出1个位)
z = x >> 2;
x: 00000000 00101001
>> 00000000 00000010
--- -------- --------
z: 00000000 00001010 01(溢出2个位)
6.6 按位取反运算(~)
按位取反运算(~)是将操作数对应的位翻转(1 变 0,0 变 1)。
示例
#include <stdio.h>
int main(int argc, char *argv[]) {
short int x = 0x29; // 00000000 00101001
short int z;
z = ~x; // z = 11111111 11010110
printf("z: 0x%04x\n", z);
return 0;
}
执行结果如下:
z: 0xffffffd6
运算过程
z = ~x;
x: ~ 00000000 00101001
--- -------- --------
z: 11111111 11010110
练习1:
输入两个无符号的整数,计算两个整数位与、位或、位异或的值并打印结果。
练习2:
输入一个整数,用有符号变量 x 绑定。
- 将 x 的第 0 位置0 后打印结果。提示:
x &= (~1);。 - 将 x 的第 1 位置1 后打印结果。提示:
x |= 0x01 << 1;。 - 将 x 的第 2 位取反后打印结果。提示:任意为和
1异或翻转,和0异或不变。