我有以下问题:在我的代码示例中,too_long_CommandFrameStruct
显示5
的大小,而所有成员加在一起具有4
的大小。如果我将联合成员的位置更改为第一个(如在shorter_CommandFrameStruct
中),则大小如预期的4
。
为什么会发生这种情况,我该如何预防?我想有结构体成员的顺序,因为结构体逐字节写入(4字节长)SPI缓冲帧。
对于5字节长的结构体,我有问题,因为在unsigned int crc
成员和union Commands cmdData
成员之间添加了一个小块。这可能会导致结构体增长到4.5,也就是5个字节。
代码可以在在线编译器中执行,例如https://www.tutorialspoint.com/compile_c_online.php
#include <stdio.h>
#include <stddef.h>
union UnspecificFrame_t
{
unsigned short RegValue;
struct /* Single Bits */
{
unsigned bit0 :1;
unsigned bit1 :1;
unsigned bit2 :1;
unsigned bit3 :1;
unsigned bit4 :1;
unsigned bit5 :1;
unsigned bit6 :1;
unsigned bit7 :1;
unsigned bit8 :1;
unsigned bit9 :1;
unsigned bit10 :1;
unsigned bit11 :1;
unsigned bit12 :1;
unsigned bit13 :1;
unsigned bit14 :1;
unsigned bit15 :1;
} __attribute__((packed, aligned(1))) Bits;
};
union Commands
{
union UnspecificFrame_t unSpecFrame;
};
/* This one should be 4 bytes long, but actually is 5 bites long */
struct too_long_CommandFrameStruct
{
unsigned int crc :4;
union Commands cmdData;
unsigned int cmdType :4;
unsigned int id :8;
}__attribute__((packed, aligned(1))) too_long_CommandFrameStruct_t;
/* When switching the first members, the size is right */
struct shorter_CommandFrameStruct
{
union Commands cmdData;
unsigned int crc :4;
unsigned int cmdType :4;
unsigned int id :8;
}__attribute__((packed, aligned(1))) shorter_CommandFrameStruct_t;
int main()
{
printf("why is this size: %dn", sizeof(too_long_CommandFrameStruct_t)); // returns 5
printf("and this one size: %d?n", sizeof(shorter_CommandFrameStruct_t)); // returns 4
return 0;
}
在C语言中,比特字段以外的对象用整数字节表示。并且要求结构体的成员在内存中的顺序与在结构体中声明的顺序一致。
当unsigned int crc :4;
时,它不需要填充一个完整的字节,因为它是一个位域,但它必须在一个或多个用于它的字节中。然后union Commands cmdData
紧随其后,占用两个字节。然后unsigned int cmdType :4;
和unsigned int id :8;
需要更多的12位,因此至少需要两个字节(假设字节是8位,这是常见的)。因此声明成员至少需要5个字节。
请注意,上面甚至没有考虑对齐;需要五个字节仅仅是因为您需要一个字节,然后两个字节,然后再两个字节。
当union Commands cmdData
是第一个时,它需要两个字节。然后它后面的三个位域占用4+4+8 = 16位,只需要两个字节。所以总共是四个字节。