与位域的结构对齐

问题描述 投票:0回答:1

为什么

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;
};
c++ bit-fields
1个回答
0
投票

位字段没有存储空间,但它们的内存位置与您提供的标量类型大小相同,因此对齐通常至少具有相同的大小,但在遇到零大小的字段之前,不会定义 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:我写“可能”是因为由编译器的实现来决定如何打包位,但这或多或少是常见的方法。出于互操作性目的,同一平台上的编译器通常是相同的,但确实存在例外。

© www.soinside.com 2019 - 2024. All rights reserved.