位段
位段(或称“位域”,Bit field)为一种数据结构,可以把数据以位元的形式紧凑的储存,并允许程序员对此结构的位元进行操作。这种数据结构的好处:
- 可以使数据单元节省储存空间,当程序需要成千上万个数据单元时,这种方法就显得尤为重要。
- 位段可以很方便的访问一个整數值的部分内容从而可以简化程序源代码。
而位域这种数据结构的缺点在于,其内存分配与内存对齐的实现方式依赖于具体的机器和系统,在不同的平台可能有不同的结果,这导致了位段在本质上是不可移植的。[1]
简介
在C语言中,位段的声明和结构(struct)类似,但它的成员是一个或多个位元的字段,这些不同长度的字段实际储存在一个或多个整型变量中。在声明时,位段成员必须是整形或枚举类型(通常是无符号类型),且在成员名的后面是一个冒号和一个整数,整数规定了成员所占用的位元数。位域不能是静态类型。不能使用&
对位域做取地址运算,因此不存在位域的指针,编译器通常不支持位域的引用(reference)。以下程序则展示了一个位段的声明:
struct CHAR
{
unsigned int ch : 8; //8位
unsigned int font : 6; //6位
unsigned int size : 18; //18位
};
struct CHAR ch1;
以下程序展示了一个结构体的声明:
struct CHAR2
{
unsigned char ch; //8位
unsigned char font; //8位
unsigned int size; //32位
};
struct CHAR2 ch2;
第一个声明取自一段文本格式化程序,应用了位段声明。它可以处理256个不同的字符(8位),64种不同字体(6位元),以及最多262,144个单位的长度(18位)。这样,在ch1这个字段对象中,一共才占据了32位的空间。而第二个程序利用结构体进行声明,可以看出,处理相同的数据,CHAR2类型占用了48位空间,如果考虑边界对齐并把要求最严格的int类型最先声明进行优化,那么CHAR2类型则要占据64位的空间。
无名位域
如果位域的定义没有给出标识符名字,那么这是无名位域,无法被初始化。[2]无名位域用于填充(padding)内存布局。只有无名位域的比特数可以为0。这种占0比特的无名位域,用于强迫下一个位域在内存分配边界对齐。
实现
通常在大端序系统(如PowerPC),安排位域从最重要字节(most-significant byte)到最不重要字节(least-significant byte),在一个字节内部从最重要位(most-significant bit)到最不重要位(least-significant bit);而在小端序系统(如x86),安排位域从最不重要字节(least-significant byte)到最重要字节(most-significant byte),在一个字节内部从最不重要位(least-significant bit)到最重要位(most-significant bit)。[3]共同遵从的原则是内存字节地址从低到高,内存内部的比特编号从低到高。
Microsoft Visual C++实现
在一个整数(integer)内的位域从最不重要位(least-significant)向最重要位(most-significant)依次分配。
相邻的两个位域如果基类型(underlying type)的长度相同,在后的位域适合当前内存分配单元且没有跨内存分配边界,那么这两个位域分配到同一个(1、2或4字节的)分配单元。[4] 这可以通俗理解为:具有相同的基类型(underlying type)长度的相邻位域尽量装入基类型的同一个对象,如果装得下的话。
参考文献
- ISO 14882 C++14 standard §9.6.1: "Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit. [Note: Bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. —end note ]"
- ISO 14882 C++14 standard §9.6.2
- . [2017-03-15]. (原始内容存档于2017-05-10).
- . [2017-03-15]. (原始内容存档于2017-03-15).