C语言中的位运算
- 结构体是唯一一种允许控制内存位(bit)的数据结构,称作位域(Bit Field)
- 位域不能离开结构体单独存在
- 位域不能成为数组,但是带位域的结构体可以成为结构体数组
- 和位域有关的代码是取决于具体机器
- 用途
- 谨慎使用内存时(需要把几个数据放进一个字(Machine Word)
- 读取非标准格式(9-Bit 整型)
- ...
位域
struct {
unsigned int a : 1; //a占1为bit,最大为2^1 - 1 = 1
unsigned int b : 3; //b占3位bit,最大为2^3 - 1 = 7
unsigned int c : 1; //c占1位bit,最大为2^1 - 1 = 1
} exmpl;
- 位域是int或者unsigned int类型
- 一位大小的位域只能是unsigned int,因为没有符号的空间
- 在内存中位域被调整成int的大小(大部分机器中4 Bytes)
用例:假设有一种机器人使用1 Byte大小的数据包进行通信,但是需要发送多个状态信息
struct device {
unsigned int active : 1;
unsigned int ready : 1;
unsigned int idle : 1;
unsigned int error : 1;
} code;
内存位置
位域也可以匿名:
struct device {
unsigned int active : 1;
unsigned int ready : 1;
unsigned int idle : 1;
unsigned int error : 1;
unsigned int : 2;
unsigned int EOR : 1;
} code;
```[图片上传失败...(image-a26aed-1554036927678)]
# 位域的大小
```c
//exmpl占12 Bytes
struct {
unsigned int a : 1;
unsigned int b : 32;
unsigned int c : 1;
} exmpl;
- 首先给a分配内存空间,计算机将位域看作int(4 Bytes)分配空间,在第一个int中存储a后还有31位
- 给b分配空间时,因为第一个int剩下的31位无法存储32位的b,所以计算机开辟第二个int来储存b
- 第二个int已经没有多余的空间储存c,计算机单独再给c开辟一个int的空间
//exmpl占8 Bytes
struct {
unsigned int a : 1;
unsigned int b : 1;
unsigned int c : 32;
} exmpl;
- 首先给a分配内存空间,计算机将位域看作int(4 Bytes)分配空间,在第一个int中存储a后还有31位
- 然后给b分配空间,因为第一个int还剩下的31位,在第一次开辟的空间中连续存储1位的b,
- 第一个int已经没有多余的空间(还剩30位)储存c(32位),计算机单独再给c开辟一个int的空间
按位运算符
各种语言中的位运算符- 位运算符通常被用来:测试位、设置位、移位
- 只有int(char)类型才可以用来位运算(一般使用char来处理bytes,int来处理words)
- 按位NOT就是反转位(1's complement)
- 按位XOR就是当且仅当一个操作数为1时,按位XOR才为1
- 逻辑运算的结果是
0
或非0
,但是位运算的结果是0
到2^n - 1
(n为一个machine word含有的位数)
位运算的用途
- 追踪错误
- 奇偶校验(Parity Check)是一种校验代码传输正确性的方法。根据被传输的一组二进制代码的数位中“1”的个数是奇数或偶数来进行校验
char get_char_from_modem(void) {
char ch;
ch = read_modem (); // 从Modem中读取一个数据
return (ch & 127);
}
奇偶校验数据
- 将bytes的第一位设置为校验位(标示剩下的7位中有1的数目是否位偶数)
- 判断校验位后,使用按位与127复制除了校验位以外的位数
2. 使用按位XOR寻找不同的位数
int x = 120;
x = 127 ^ x;
不同的位数
- x为120,即差的数为7(127-120)
3. 使用求反来加密数据
其他操作
1. 16进制表示
#include <stdio.h>
int main(){
int n = 0x01A1;
n = n & 0xFF; /* Note: n &= 0xFF; is the same */
printf("%x\n",n); return 0;
}
//输出:a1
16进制表示
2. 使用Bit Mask检查16进制的具体位数:
//检查整数y右边的第三位是1还是0
int mask = 0x0004;
if ((y & mask) == 0)
printf("Third bit = 0\n");
else
printf("Third bit = 1\n");
Bit Mask检查
3. 使用Bit Mask修改部分位数:
//让左边的4位归零,右边的4位不动
char cmask = 0x0F;
c &= cmask;
修改部分位数
4. 移位操作:
- 对于左移位,全部填充的位数都是0,
- 对于右移位,如果标示位(第一位)是0,则全部填充0;如果标示位是1,则取决于具体实现,通常情况下填充1
- 数值上左移位乘2的次方倍,反之除
int n = 0x01A1;
int n1, n2, n3, n4;
n1 = n << 1; /* Value of n1 = 0x0342 */
n2 = n << 4; /* Value of n2 = 0x1A10 */
n3 = n >> 1; /* Value of n3 = 0x00D0 */
n4 = n >> 4; /* Value of n4 = 0x001A */
移位操作
网友评论