struct 位域结构名
{
位域类型 位域名:占用位的长度;(位域列表)
};
1、使用位域可能不如使用位运算符的执行速度快,但是位域使程序更容易阅读。
2、如果某个作用域中定义了位域结构,则在该作用域中就不能使用typedef或#define来定义与位域结构名相同的类型名。
3、在之前的标准中,位域类型必须是int、unsigned int或signed int。使用int会引起二义性,因为一些编译器将位域的最高位作为符号位,而其他一些编译器则不会;另一方面,如果使用signed int类型若使用到了正负,也会存在问题。故建议使用unsigned int类型。
在C99新标准中,编译器还允许使用_Bool类型,不过一些编译器在具体实现时,额外支持了char、unsigned char、signed char、enum类型。
4、每个位域结构都会定义自己的作用域,所以花括号内部定义的位域名可以和其他作用域中的变量同名,而内部不可以同名。
α、C语言允许省略位域的名字。
5、占用位的长度可以根据需要进行配置,但是不能超过位于类型所占的总位数。
β、在省略位域名时可以为零。
6、C语言不允许将&运算符用于位域,所以,向scanf这样的函数无法直接向位域中存储数据。可以通过使用一个临时变量的方法间接存储。
7、位域内存分布
7.1、当编译器处理位域这种结构的声明时,会将位域逐个放入存储单元,位域之间没有间隙,直到剩下的空间不够用来放下一个位域了。这时,一些编译器会跳到下一个存储单元的开始,另一些则会将位域拆开跨存储单元存放。位域的存放循序(从左到右还是从右到左)也由实现决定。
7.2、上面第4点提到的省略位域名,经常用来作为字段间的“填充”,以保证其它位域存储在适当的位置。
7.3(γ)、另一个用来控制位域存储的技巧是指定未命名的字段长度为0。这是给编译器一个信号,告诉编译器将下一个位域在一个存储单元的起始位置对齐。
7.4、
相邻位域字段的类型 | 位宽之和与类型比较 | 结果 |
相同 | 小于 | 紧邻的存储在该类型大小的空间中(压缩) |
相同 | 大于 | 大于的部分从下一个该类型大小的空间中开始存储 |
不同 | 依编译器而定,(GCC会压缩,VS、VC不会) |
7.5、只有相邻的位域才能被压缩,若位域列表之间有一个非位域则会被分成两部分,两部分单独考虑。
7.6、因为存在数据内存对齐问题,所以整个位域结构体的总大小为最宽基本类型成员大小的整数倍,这一点与结构体类型是一致的。
8、若位段出现在表达式中,则会自动进行整型提升,转换为int或unsigned int。
总结:位域使用的最佳策略是:
1、位域的类型要使用合适的且占用内存最小的无符号类型。
2、整个位域列表尽量使用相同的类型(数据对齐问题会引起不必要的内存消耗)。
2、不要在位域列表中间插入非位域。
3、合理的布局位域列表的顺序。