在GCC C中,我如何获得一个打包结构数组,其中数组中的每个条目都是对齐的?
(FWIW,这是在PIC32上,使用MIPS4000架构)。
我有这个(简化):
typedef struct
{
short read; // next buffer to read
short write; // next buffer to write
short count; // number of packets stored in q
short buffers; // number of buffers allocated in q
RADIO_PACKET q[RADIO_RX_PACKET_BUFFERS];
} RADIO_PACKET_QUEUE;
RADIO_PACKET在内部打包。
然后我有RADIO_PACKET_QUEUE,这是RADIO_PACKETs的队列:
RADIO_PACKET_QUEUE rpq;
int foo = *(int*) &(rpq.q[1]);
我希望数组q []中的每个RADIO_PACKET都以对齐的地址(模4地址)开始。
但是现在GCC没有对齐它们,所以当我尝试将q [n]读作一个单词时,我得到地址异常。例如,这给出了一个例外:
TextView
也许这是因为我将RADIO_PACKET声明为打包的方式。
我希望每个RADIO_PACKET在内部保持打包状态,但是希望GCC在每个数组元素之后根据需要添加填充,以便每个RADIO_PACKET从对齐的地址开始。
我该怎么做?
答案 0 :(得分:3)
由于您指定使用GCC,因此您应该查看类型属性。特别是,如果您希望{4}在4字节(或更宽)边界上对齐,那么您将在类型上使用RADIO_PACKET
。应用于__attribute__((aligned (4)))
时,它描述了整个struct
实例的对齐方式,而不是(直接)任何单个成员的对齐方式,因此可以将其与属性{{1}一起使用}:
struct
packed
属性可以防止结构元素之间的填充,但不会阻止结构表示中的尾部填充,这与确保数组的每个元素所需的对齐所必需的完全相同指定类型的。那么你不应该在typedef struct __attribute__((aligned(4), packed))
{
uint8_t frameLength;
unsigned frameType :3;
uint8_t payloadBytes;
uint8_t payload[RADIO_RX_PAYLOAD_WORST];
} RADIO_PACKET;
的声明中做任何特别的事情。
这比你提出的替代方案更清晰,更清晰,但它是GCC特有的。由于你已经是GCC特定的,我不认为这是一个问题。
答案 1 :(得分:2)
您可以将打包的结构包裹在另一个未对齐的结构中。然后你从这个未对齐的结构做数组。
解决方案2可以是,在打包结构的末尾添加虚拟成员char []。在这种情况下,您需要以某种方式计算它,可能是手动计算。
我还建议您重新排列结构,先放置较长的成员并将uint8_t
成员放在最后(假设您有16/32位成员而不进行某些硬件映射)。
答案 2 :(得分:1)
我想我已根据问题评论中@Nick的暗示解决了这个问题。
我在RADIO_PACKET附近添加了一个RADIO_PACKET_ALIGNED包装器。这包括计算填充。
然后我在RADIO_PACKET_QUEUE结构中用RADIO_PACKET替换RADIO_PACKET_ALIGNED。
似乎工作:
typedef struct
{
RADIO_PACKET packet;
uint8_t padding[3 - (sizeof(RADIO_PACKET) + 3) % 4];
} RADIO_PACKET_ALIGNED;
typedef struct
{
short read; // next buffer to read
short write; // next buffer to write
short count; // number of packets stored in q
short buffers; // number of buffers allocated in q
RADIO_PACKET_ALIGNED q[RADIO_RX_PACKET_BUFFERS];
} RADIO_PACKET_QUEUE;
感谢所有评论者!
编辑:包装器的更便携版本将使用:
uint8_t padding[(sizeof(int) - 1) - (sizeof(RADIO_PACKET) + (sizeof(int) - 1)) % sizeof(int)];