位运算

6种位运算

& 位与运算 、 | 位或运算 、 ~ 位反运算 、 ^ 异或运算 、 >> 右移位运算 、 << 左移位运算

1. 位与运算(&)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdint.h>
int main() {
/**
* & 位与运算
* 对比两个二进制数据的位,如果对应的位数均为1则结果为1,否则为0
*/
int a = 0b1001;
int b = 0b1010;
printf("%d\n",a & b); //位与 运算后的二进制结果为 0b1000 所以输出的十进制结果为8
int8_t c = 20; //对应8位的二进制为 0001 0100
int8_t d = 30; //对应8位的二进制为 0001 1110
printf("%d\n",d & c); //位与 运算后的二进制结果为 0001 0100 所以输出的十进制结果为20
}

2. 位或运算(|)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdint.h>
int main() {
/**
* | 位或运算
* 对比两个二进制数据的位,如果对应的位数均为0则结果为0,否则为1
*/
int a = 0b1001;
int b = 0b1010;
printf("%d\n",a | b); //位或 运算后的二进制结果为 0b1011 所以输出的十进制结果为11
int8_t c = 20; //对应8位的二进制为 0001 0100
int8_t d = 30; //对应8位的二进制为 0001 1110
printf("%d\n",d | c); //位或 运算后的二进制结果为 0001 1110 所以输出的十进制结果为30
}

3. 位反运算(~)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <stdint.h>
int main() {
/**
* ~ 位反运算
* 对二进制数据进行取反,1变成0、0变成1
*
*
* 假设有一 int 类型的数,值为5,那么,我们知道它在计算机中表示为:
* 00000000 00000000 00000000 00000101
* 5转换成二制是101,不过int类型的数占用4字节(32位),所以前面填了一堆0。
*
* 二进制正数与负数的表示:前面的一位表示符号位、正数为0,负数为1
*
* 现在想知道,-5在计算机中如何表示?
* 在计算机中,负数以其正值的补码形式表达。
* 什么叫补码呢?这得从原码,反码说起。
*
* 原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。
* 比如 00000000 00000000 00000000 00000101 是 5的 原码。
*
* 反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码。
* 取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)
* 比如:将00000000 00000000 00000000 00000101每一位取反,得11111111 11111111 11111111 11111010。
* 称:11111111 11111111 11111111 11111010 是 00000000 00000000 00000000 00000101 的反码,反码是相互的
*
* 补码:反码加1称为补码。
* 也就是说,要得到一个数的补码,先得到反码,然后将反码加上1,所得数称为补码。
* 比如:00000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。
* 那么,补码为:11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011
*/
int8_t a = 3; //3对应8位的二进制数据为 0000 0011
a = ~a; //3位返 运算后的结果为 1111 1101
printf("%d\n",a); //输出结果为-4
uint8_t b = 5; //无符号的最大储值是255
b = ~b; //无符号的5位返后的值为 255 - 5 = 250
printf("%d\n",b); //结果为250 无符号的int位反后的值为最大储值减要位反的值
}

4. 异或运算(^)

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdint.h>
int main() {
/**
* ^ 异或
* 对比两个二进制数据的位,如果对应的位数不相同则为1,否则为0
*/
int8_t a=0b0001;
int8_t b=0b0011;
printf("%d\n", a^b); //异或运算后的结果为0b0010、输出结果为2
return 0;
}

5. 右移位运算(>>)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main() {
/**
* >> 右移
* 示例:
* 2 >> 1 = 1 // 0b0010 左移一位后的结果为 0b0001
* 和左移位相反将二进制数向右移位
*/
printf("%d\n", 5>>1); //0b0101移一位为0b0010 结果为2
printf("%d\n", 5>>2); //0b0101移二位为0b0001 结果为1
printf("%d\n", 5>>3); //0b0101移三位为0b0000 结果为0
printf("%d\n", 5>>4); //0b0101移四位为0b0000 结果为0
printf("%d\n", 6>>1); //0b0110移一位为0b0011 结果为3
return 0;
}

6. 左移位运算(<<)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
int main() {
/**
* << 左移
* 示例:
* 2 << 1 = 4 // 0b0010 左移一位后的结果为 0b0100
* 将二进制数向左移位、移位后右边用0填充
* 向左移一位后的值,刚好为原值乘2。
* 用这种移位的方式作乘法运算是最快的
*/
printf("%d\n", 5<<1); //0b0101移一位为0b1010 结果为10 类似 5*2
printf("%d\n", 5<<2); //0b0101移二位为0b10100 结果为20 类似 5*2*2
printf("%d\n", 5<<3); //0b0101移三位为0b101000 结果为40 类似 5*2*2*2
printf("%d\n", 5<<4); //0b0101移四位为0b1010000 结果为80 类似 5*2*2*2*2
return 0;
}

7. 示例-使用位运算提取颜色通道值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdint.h>
int main() {
/**
* 通常用十六进制保存颜色值
* 0xFFEEDDCC 每两位一个通道,四个通道分别表示 ARGB(Alpha,Red,Greed,Blue)
* 可以通过红绿蓝及透明度混合成任何一种颜色
*/
uint32_t color = 0xFFEEDDCC;
/**
* 现在要通要取红色通道的值
* 首先用位与运算去掉其它通道的值
* 0b11111111 11101110 11011101 11001100 //color值
* 0b00000000 11101110 00000000 00000000 //位与0x00FF0000后的值
*/
uint32_t temp = color & 0x00FF0000;
//再将0b00000000 11101110 00000000 00000000右移16位所得的即为红色通道的值
uint8_t red=temp>>16; //红色通道EE,结果输出238
printf("%d\n", red);
return 0;
}
坚持原创技术分享,您的支持将鼓励我继续创作!