具有位字段的C++结构大小

Dam*_*ler 4 c++ gcc arm

我有以下三个工会:

typedef union {
    struct {
        uint16_t : 2;
        uint16_t numberOfWords : 10;
        uint16_t  : 4;
        uint16_t dataFormat : 8;
        uint16_t : 8;
    } bf;
    uint32_t dw;
} HeaderT;

typedef union {
    struct {
        uint16_t : 4;
        uint16_t lsb : 8;
        uint16_t  : 4;
        uint16_t msb : 8;
        uint16_t : 8;
    } bf;
    uint32_t dw;
} RegisterT;

typedef union {
    struct {
        uint16_t : 2;
        uint16_t lsb : 10;
        uint16_t : 2;
        uint16_t msb : 10;
        uint16_t : 8;
    } bf;
    uint32_t dw;
} BinT;
Run Code Online (Sandbox Code Playgroud)

我得到sizeof(HeaderT)== 4,sizeof(RegisterT)== 4,但sizeof(BinT)== 8!我不知道为什么.

typedef union {
    struct {
        uint16_t : 2;
        uint16_t lsb : 10;
        uint16_t : 2;
        uint16_t msb : 10;
        uint16_t : 8;
    } bf __attribute__((packed));
    uint32_t dw;
} BinT;
Run Code Online (Sandbox Code Playgroud)

没有帮助.我需要BinT为32位宽; 它的内存映射到FPGA上的一堆寄存器.

有谁知道发生了什么?我在ARMv7上使用gcc.但是,我在x86_64 VirtualBox VM上的gcc上看到了相同的内容.

谢谢.

eer*_*ika 7

位字段成员不能拆分为两个(或更多)基元.那么,就标准而言,根本不保证包装.它的实现已定义.但这是一个典型的限制,如果实现确实打包位字段.

让我们看看GCC手册中有关实现定义行为的内容:

  • 位域是否可以跨越存储单元边界(C90 6.5.2.1,C99和C11 6.7.2.1).

由ABI决定.

我不确定这是否适用于ARM,但通常GCC符合64位Itanium规范.

(假设从左到右打包)原语之间的"位分布"现在是:

uint16_t: 2 10 2 // 10 won't fit anymore
uint16_t: 10     // 8 won't fit anymore
uint16_t: 8
Run Code Online (Sandbox Code Playgroud)

这三个uint16_t不可能适合32位.

这个:

union BinT {
    struct {
        uint32_t : 2;
        uint32_t lsb : 10;
        uint32_t : 2;
        uint32_t msb : 10;
        uint32_t : 8;
    } bf;
    uint32_t dw;
};
Run Code Online (Sandbox Code Playgroud)

从现在开始工作所有位字段都可以共享一个原语.

好的,所以通过将uint16_t改为无符号,我得到预期的结果.但我不明白为什么

unsigned 然后看起来是32位宽.

我需要BinT为32位宽

鉴于此要求,如果您希望程序可移植,则可能应避免使用位字段.如果使用位字段,则依赖于实现定义的行为.