C语言中的位运算

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,但是位运算的结果是02^n - 1(n为一个machine word含有的位数)


位运算的用途

  1. 追踪错误
  • 奇偶校验(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  
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 */ 
移位操作

你可能感兴趣的:(C语言中的位运算)