在编写一个C++小程序时,遇到了与位域相关的问题,为此查看相关资料并通过试验进行验证。
首先,查看C++Primer中的相关介绍,主要内容如下:
1. 位域在内存中的布局是机器相关的;
2. 位域必须是整型数据类型,可以是signed或unsigned;
3. 地址操作符(&)不能用于位域。
试验验证:
1. 位域的对齐及长度问题(暂时只考虑将结构体对齐方式设置为1字节的情况)
考虑下面的三种位域定义,其长度分别是多少?
struct BF1{
char s1: 6;
char s2: 3;
char s3: 6;
char s4: 3;
char s5: 6;
char s6: 3;
};
struct BF2{
char16_t s1: 6;
char16_t s2: 3;
char16_t s3: 6;
char16_t s4: 3;
char16_t s5: 6;
char16_t s6: 3;
};
struct BF3{
char32_t s1: 6;
char32_t s2: 3;
char32_t s3: 6;
char32_t s4: 3;
char32_t s5: 6;
char32_t s6: 3;
};
答案是:
下面分析造成长度不同的原因,查看3个位域类型中,各位段的对齐方式。
分别定义3种类型的变量,并将其中3bit宽度的位段各位全置为1:
struct BF1 bf1;
struct BF2 bf2;
struct BF3 bf3;
memset(((unsigned char*)&bf1),0,sizeof(BF1));
memset(((unsigned char*)&bf2),0,sizeof(BF2));
memset(((unsigned char*)&bf3),0,sizeof(BF3));
bf1.s1 = bf2.s1 = bf3.s1 = 0;
bf1.s2 = bf2.s2 = bf3.s2 = 7;
bf1.s3 = bf2.s3 = bf3.s3 = 0;
bf1.s4 = bf2.s4 = bf3.s4 = 7;
bf1.s5 = bf2.s5 = bf3.s5 = 0;
bf1.s6 = bf2.s6 = bf3.s6 = 7;
然后分别输出bf1、bf2、bf3的二进制数据内容:
可以看出,使用不同的数据类型来定义位域中各个位段,其内部各位段的分布是不同的。
使用char型定义(8位对齐):
使用char16_t型定义(16位对齐):
使用char32_t型定义(32位对齐):
在bf1中,使用char类型定义位域的各个位段时,将以char类型的长度(8bit)来分配空间,首先为s1分配6bit,然后分配s2的3bit时,已经超出了8bit,在一个char型长度中放不下,因此位段s2被分配到下一个char长度单元中;同理分配s3时,也无法与s2分配到同一个char长度单元中,于是分配到第3个char长度单元中。
同理,在bf2、bf3中,将分别以16位、32位为长度单位来分配各个位段,于是在同一个长度单位中能分配下的位段也不同,就造成了存放各位段位置的不同。
最后,再看下《C++编程金典》中对使用位域的提醒: