位域
一、定义:
有些信息在存储时,并不需要占用一个完整的字节,而只需要占一个或几个二进制位。例如在存放一个开关量时,只有0和1两种状态,只需要用一位二进制位即可。为了节省存储空间,并且为了让处理变得更便捷,C语言又提供了一种数据结构,称为“位域”或者“位段”。所谓位域,就是把一个字节中的二进制位划分为不同的区域,并说明每个区域的位数。每个域都有一个域名,允许程序中按照域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
二、结构:
位域的结构与结构体相似
struct <位域结构名>
{
...
<类型说明符> <位域名> : <位域长度> // 位域列表
...
};
ex:
struct Demo
{
int a : 8;
int b : 2;
int c : 4;
};
而位域变量的说明也与结构体变量的说明方式相同,可以采用先定义后说明、同时定义说明、直接说明这三种方式,例如:
方式1:
struct Demo
{
int a : 8;
int b : 2;
int c : 4;
}demo1;
方式2:
struct Demo
{
int a : 8;
int b : 2;
int c : 4;
};
struct Demo demo1;
方式3:
typedef struct Demo
{
int a : 8;
int b : 2;
int c : 4;
}De;
De demo1;
这三种方式中的demo1均为Demo的变量,且占两个字节,其中位域a占8bit,位域b占2bit,位域c占4bit。
三、几点注意事项:
- 一个位域必须存储在同一个字节中,不能跨字节存储。如一个字节所剩空间不能存储下一个位域的时候,应从下一个字节开始存储。也可以有意使某个位域从下一单元开始,如:
struct Demo
{
int a : 4;
int : 0;//空域
int b : 6;//从第二个字节开始存放
};
在这个位域定义中,a占第一个字节的4bit,这个字节的另4bit填0表示不使用,b从第二个字节开始,占4bit。
-
由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说位域的不能超过8bit;
-
位域可以无位域名,这时它只用作填充或调整位置。无名的位域是不能使用的。例如:
struct Demo
{
int a : 4;
int : 2; // 这2bit不能使用
int b : 2;
};
总结:从以上三点来看,位域的本质就是一种结构类型,不过其成员是按二进制位分配的。
四、位域的使用:
位域的使用与结构体相同,其一般形式为:<位域变量名>.<位域名>,位域允许各种格式的输出。
ex:
struct Demo
{
unsigned int a : 1;
unsigned int b : 4;
unsigned int c : 3;
}demo1,*pdemo;
void main()
{
demo1.a = 1;
demo1.b = 15;
demo1.c = 7;
printf("demo1.a = %d, demo1.b = %d, demo1.c = %d\n",demo1.a,demo1.b,demo1.c);
pdemo = &demo1;
pdemo->a = 0;
pdemo->b &= 1;
pdemo->c |= 3;
printf("pdemo->a = %d, pdemo->b = %d, pdemo->c = %d\n",pdemo->a,pdemo->b,pdemo->c);
}
上例程序中定义了位域结构Demo,其中有三个位域a,b,c。说明了该位域结构的两个变量demo1和指向Demo类型的指针变量pdemo,这表示位域也是可以使用指针的。
同时也给三个位域进行了赋值(注意赋值不能超过该位域的允许范围)。上例也表示了位域也可以进行复合的位运算。
五、含位域结构体的sizeof
位域结构的成员不能单独被取sizeof值
C99规定int、unsigned int、bool可以做位域的类型,但编译器几乎都对此做了扩展,允许其他类型的存在。
使用位域的主要目的在于压缩内存,大致规则如下:
如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
如果相邻位域字段的类型相同,且其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
如果相邻位域字段的类型不同,则各个编译器的具体实现有所差异,VC6不压缩,而Dev C++压缩;
如果位域字段之间插着非位域字段,则不进行压缩;
整个位域结构体的总体大小为最宽的基本类型成员大小的整数倍。
ex:
例一:
struct Demo
{
char c1 : 3;
char c2 : 4;
char c3 : 5;
};
sizeof(Demo) = 2;
位域类型为char,第一个字节仅仅能存储下c1和c2,所以c3只能存储到第二个字节中去。
例二:
struct Demo
{
char c1 : 3;
short s2 : 4;
char c3 : 5;
};
在VC中: sizeof(Demo) = 6。
因为字节对齐,所以c1要对齐s2,即c1要占用2个Byte,s2要占用2个Byte,而c3占用1个Byte。
又因为整个结构大小最宽的类型为short,所以要是short的整数被,所以还需要填充1个Byte,所以sizeof(Demo) = 6。
在Dev C++中,sizeof(Demo) = 2;
例三:
struct Demo
{
char c1 : 3;
char c2;
char c3 : 5;
};
sizeof(Demo) = 3;
c1占1个bit,c2占1个bit,c3占一个bit。
对作者3w的《C++中的位域详解》这一篇博客进行了整理,以供学习参考
原文链接:《C++中的位域详解》