为什么
sizeof(A)
是12?
应该是:
float(4) + x_0-pad(2) + y_1(2) = 8
如果全部与
float
对齐,我该如何避免这种情况?
struct A
{
int x_0 : 1;
int x_1 : 1;
int x_2 : 1;
int x_3 : 2;
int x_4 : 2;
int x_5 : 2;
int x_6 : 3;
uint16_t pad : 4;
uint16_t y_1;
float y_2;
};
位字段没有存储空间,但它们的内存位置与您提供的标量类型大小相同,因此对齐通常至少具有相同的大小,但在遇到零大小的字段之前,不会定义 a 中的顺序- “相同类型的非零位域序列”。
在你的情况下,在小端系统上你的结构是可能要么像
那样组织<32bit location #0> x_6 x_5 x_4 x_3 x_2 x_1 x_0 ...
<16bit location #1> pad
uint16_t y_1;
float y_2;
或者它可以分隔字节(不跨字节边界打破字段)
<8bit location #0> x_4 x_3 x_2 x_1 x_0 ...
<8bit location #1> x_6 x_5 ...
<an optional 16bit padding>
<16bit location #2> pad
uint16_t y_1;
float y_2;
大多数现代编译器使用第一种方法,并保证非零字段尽可能多地填充相关位置。这就是为什么你的大小为 12 个字节:一个
int
(4) + 2 uint16_t
(2) + float
(4)。
注意:您还可能遇到一个编译器,其中
int
是 16 位,然后它就会像您期望的那样工作。
在大端或某些灵活的架构上可以
<32bit location #0> ... x_0 x_1 x_2 x_3 x_4 x_5 x_6
<16bit location #1> pad
uint16_t y_1;
float y_2;
不同的类型导致需要考虑新的位置。您可以添加零大小的字段:
int x_break: 0;
任何地方都可以分解序列并强制执行部分排序。由
...
标记的未使用位不被正式视为填充,但工作原理类似。
除非用户更改
struct
上的对齐要求,否则可以在<location #2> pad
之前/之后进行填充以满足int
的对齐要求。
注意:您甚至不能保证位域不再从结构体的开头开始,只能保留与其他结构体成员相关的一般顺序。
注2:我写“可能”是因为由编译器的实现来决定如何打包位,但这或多或少是常见的方法。出于互操作性目的,同一平台上的编译器通常是相同的,但确实存在例外。