本文中的代码,插图来自:
https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?redirectedfrom=MSDN&view=msvc-160
在C++的结构体或者类中,我们可以通过位域运算符来进一步限定成员变量占几个bit,比如
// bit_fields1.cpp
// compile with: /LD
struct Date {
unsigned short nWeekDay : 3; // 0..7 (3 bits)
unsigned short nMonthDay : 6; // 0..31 (6 bits)
unsigned short nMonth : 5; // 0..12 (5 bits)
unsigned short nYear : 8; // 0..100 (8 bits)
};
在上面的结构体中,我们通过位域运算符限定:nWeekDay占3个比特位,nMonthDay占6个比特位,nMonth占5个比特位。
那么当我们使用了位域运算符后,各个数据成员在内存中时怎么分配的呢,还是以上面的结构体为例,它的内存分布如下图所示:
由于unsigned short 类型是2个字节,16位比特,在内存排布的时候是以sizeof(unsigned short)= 16 bits为单位,当放完nWeekDay,nMonthDay,nMonth后,第一个unsigned short只剩下2 bits的空间,nYear占8 bits,如果从第一个unsigned short剩余的2bits开始放nYear,那nYear就溢出了,这时候,我们就舍弃这两个bits,从第二个新的unsigned short的开始处开始存放nYear。
未命名域
有时候,我们也可用未命名域来填充一个分配单元中剩下的bit,比如下面的例子:
// bit_fields2.cpp
// compile with: /LD
struct Date {
unsigned nWeekDay : 3; // 0..7 (3 bits)
unsigned nMonthDay : 6; // 0..31 (6 bits)
unsigned : 0; // 未命名域,unamed field, Force alignment to next boundary.
unsigned nMonth : 5; // 0..12 (5 bits)
unsigned nYear : 8; // 0..100 (8 bits)
};
上面这个struct的内存分布如下所示:
一个unsigned 类型,占4个字节(32 bit),nWeekDay, nMonthDay 共占用9 bits, 还剩下23 bits, unsigned :0 是一个未命名域,它的作用就是占用剩下的23 bits,这样nMonth 就可以从一个新的unsigned 类型的起始地址开始排布了 。