我怀疑我的编译器在64位机器上使用32位编译器(GCC MinGW)。 当我使用这个结构时:
struct S
{
unsigned int a : 2;
unsigned int b : 3;
unsigned int c : 4;
_Bool d : 1;
} s;
sizeof s
返回8,因此我的编译器正在使用我的机器字,即8字节(64位)用于打包位字段。为什么编译器是32位?实际上sizeof(int)
给了我4个。
此外,如果我将我的结构声明为:
struct S
{
char a;
char b;
char c;
_Bool d;;
} s;
sizeof s
给我4,所以最好以这种方式打包结构以节省更多空间。
所以经常说使用带结构的位字段可以节省空间......但我认为这并不总是如此......我是否缺少一些信息?
答案 0 :(得分:4)
Bitfields主要是实现定义的,甚至是未指定的。
我的猜测是从unsigned int
切换到_Bool
会使编译器启动一个全新的位字段。
无论如何,你对最终决议是对的:
如果您想要可靠和/或便携的东西,请自行包装。
这里是C99 +修正案(n1570)的所有相关部分。
6.7.2.1结构和联合说明符
[...]
5位字段的类型应为_Bool
,signed int
,unsigned int
或其他实现定义类型的限定或非限定版本。它是实现定义的,是否允许原子类型 [...]
10 10位字段被解释为具有由指定位数组成的有符号或无符号整数类型.125)如果将值0或1存储到类型为_Bool
的非零宽度位字段中,比特字段的值应等于存储的值;一个_Bool
位字段具有_Bool
的语义 11实现可以分配任何足够大的可寻址存储单元来保存位域。如果剩余足够的空间,则紧跟在结构中的另一个位字段之后的位字段将被打包到相同单元的相邻位中。如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的。单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的。可寻址存储单元的对齐未指定 12没有声明符但只有冒号和宽度的位字段声明表示未命名的位字段.126)作为特殊情况,宽度为0的位字段结构成员表示没有其他位字段将被打包到放置前一个位域(如果有的话)的单元中 [...]
15在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址。指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在其开头 [...]