编译器通常倾向于将位域打包在一个单词中,从而减少结构的整体大小。这种打包是以对位域成员的访问速度较慢为代价的。例如:
struct Bitfields
{
unsigned int eight_bit : 8;
unsigned int sixteen_bit : 16;
unsigned int eight_bit_2 : 8;
};
可能包装为
0 8 24
-----------------------------------------------------
| eight_bit | sixteen_bit | eight_bit_2 |
-----------------------------------------------------
每次访问sixteen_bit
它都会产生移位和按位 & 操作。
另一方面,如果你这样做
struct NonBitfields
{
uint8_t eight_bit;
uint16_t sixteen_bit;
uint8_t eight_bit_2;
};
然后编译器通常会在单词边界对齐成员并将其布局为:
0 8 16 24
-----------------------------------------------------
| eight_bit | | sixteen_bit |
-----------------------------------------------------
| eight_bit_2| |
-----------------------------------------------------
与位域相比,这会浪费更多空间,但无需移位和屏蔽即可更快地访问成员。
以下是其他一些区别:
- 您不能申请
sizeof
位域成员。
- 您不能通过引用传递位域成员。
在可移植性方面,这两个选项都应该适用于任何符合标准的编译器。如果您在将结构写入文件或套接字时表示不同平台之间的二进制可移植性,那么对于任何一种情况,所有赌注都没有。
在偏好方面,我会选择使用uint16_t
而不是位域,除非有充分的理由将这些域打包在一起以节省空间。如果bool
结构中有很多 s,我通常会使用位域将这些布尔标志压缩到同一个单词中。