我已经定义了一个联合结构,如下所示。
typedef union {
struct {
uint8_t id : 7;
uint8_t age : 1;
uint16_t index : 16;
uint8_t class : 4;
uint8_t reserved : 4;
} fields;
uint32_t value[1];
} entry_t;
在我的主要功能中,我使用并集的“值”成员传递一些数据,然后使用“字段”结构打印出数据。我还打印出结构的大小。
int main()
{
entry_t entry;
entry.value[0] = 0xACEDBEEF;
printf("entry.fields.id = %x \n", entry.fields.id);
printf("entry.fields.age = %x \n", entry.fields.age);
printf("entry.fields.index = %x \n", entry.fields.index);
printf("entry.fields.class = %x \n", entry.fields.class);
printf("entry.fields.reserved = %x \n", entry.fields.reserved);
printf("sizeof(entry): %d \n", sizeof(entry));
return 0;
}
这是我在控制台上看到的:
entry.fields.id = 6f
entry.fields.age = 1
entry.fields.index = aced
entry.fields.class = d
entry.fields.reserved = f
sizeof(entry): 8
我的问题是: 1)为什么我看不到entry.fields.index是“ EDBE”。这就是我所期望的。 2)为什么sizeof(entry):8?我希望是4
有趣的是,如果我更改结构以使“ fields.index”的定义如下(uint32_t而不是uint16_t):
uint32_t index : 16;
然后它按我的预期工作(即entry.fields.index = 0xEDBE,并且sizeof(entry)= 4)。
为什么编译器将两种情况区别对待?
答案 0 :(得分:0)
两个作用是字节顺序和对齐。 您的机器似乎以小字节序格式存储数据,即最低有效字节存储在最低地址。因此,您的初始化程序实际上是:
entry.fields.id = (0xef >> 1) & 0x7f;
entry.fields.age = (0xef >> 7) & 1;
entry.fields.index = 0xaced;
entry.fields.class = random stack data & 0xf;
entry.fields.reserved = random stack data & 0xf;
由于entry.fields.index是uint16_t,因此需要中断位字段序列才能插入填充或对齐字节。您之前的字段(id,age)导致16位类型未对齐,编译器对其进行了更正,这使您的“ 0xbe”消失了。
如果您稍稍更改定义:
struct {
unsigned id: 7, age:1, index :16, class:4, reserved:4;
} fields;
您可能会看到更接近您期望的内容。请注意删除了“ uint32_t”,这对于位字段而言有点自命不凡;没有伤害,只是丑陋的阅读。
您以原始格式为位字段提供对齐约束: id,age,class,reserved 不能跨越8位边界。索引不能跨越16位边界。当到达索引分配点时,必须引入8位填充来满足对齐约束。
我给 id,age,index,class,reserved 的简短形式不能跨越32位边界;编译器可以在一个单词内容纳的东西。