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

时间:2016-01-28 08:22:03

标签: 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;

我得到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;

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

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

感谢。

1 个答案:

答案 0 :(得分:7)

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

让我们看一下GCC manual关于实现定义行为的内容:

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

由ABI决定。

我不确定这是否适用于ARM,但通常GCC符合64-bit Itanium spec

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

uint16_t: 2 10 2 // 10 won't fit anymore
uint16_t: 10     // 8 won't fit anymore
uint16_t: 8

这三个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;
};

从现在起,所有位字段都可以共享一个原语。

  

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

然后

unsigned似乎是32位宽。

  

我需要BinT为32位宽

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