我有以下三个工会:
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上看到了相同的内容。
感谢。
答案 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位宽
鉴于此要求,如果您希望程序可移植,则可能应避免使用位字段。如果使用位字段,则依赖于实现定义的行为。