C语言 中结构体的位域(位段)

时间:2021-10-30 10:47:06
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。

例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。

为了节省存储空间并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。

1.位域的声明

位域变量的声明与结构变量声明的方式相同。 如:

Struct sample{

  int a:7; //类型说明符 位域名:位域长度

  int b:2;

  int c:6;

}data;

其中,data为sample变量,共占两个字节。其中位域a占第一个字节的7位,位域b占第二个字节的低2位,位域c占第二个字节的高6位。

2.位域的对齐

如果结构体中含有位域(bit-field),那么VC中准则是:

  1) 如果相邻位域字段的类型相同且其位宽之和小于声明数据类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

  2) 如果相邻位域字段的类型相同但其位宽之和大于类型的sizeof大小(如:char 的位域长度不能超过8,int的字节长度不能超过32),则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

  3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;

  系统会先为结构体成员按照对齐方式分配空间和填塞(padding),然后对变量进行位域操作。



位域可以有无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:

Struct sample{

  char a:7; //类型说明符 位域名:位域长度

  char b:2;

  char :2;

char c:2 //无位域名的位数 直接跳过且这2位不能使用

}data;







#include <stdio.h>

#include <stdlib.h>

#include <memory.h>



struct A{ //结构体字节长度为8

char a:8; //占用第一个字节的8位

unsigned int b:5; //占用第五个字节的低5位

unsigned int c:3; //占用第五个字节的高3位

};



int main()

{

char testArry[10] = "0123456789";

char testB[10] = {0};

struct A d;



memcpy(&d, testArry, sizeof(d));



printf("%d ", sizeof(d));

printf("%d ", d.a);

printf("%d ", d.b);

printf("%d ", d.c);



system("pause");

return 0;

}



编译运行输出结果:8 48 20 1

00110111 00110110 00110101 00110100 00110011 00110010 00110001 00110000