如何在 GCC C 中获取对齐的打包结构数组?

How to get aligned array of packed structs in GCC C?

在 GCC C 中,我怎样才能得到一个压缩结构数组,其中数组中的每个条目都是对齐的?

(FWIW,这是在 PIC32 上,使用 MIPS4000 架构)。

我有这个(简体):

  typedef struct __attribute__((packed))
  {
      uint8_t     frameLength; 
      unsigned    frameType       :3;
      uint8_t     payloadBytes;  
      uint8_t     payload[RADIO_RX_PAYLOAD_WORST];
  } RADIO_PACKET;

RADIO_PACKETs内部包装。

然后我有RADIO_PACKET_QUEUE,这是一个RADIO_PACKETs的队列:

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;

我希望数组 q[] 中的每个 RADIO_PACKET 都从对齐地址(模 4 地址)开始。

但是现在 GCC 没有对齐它们,所以当我试图将 q[n] 读为一个词时,我遇到了地址异常。例如,这给出了一个例外:

RADIO_PACKET_QUEUE rpq;
int foo = *(int*) &(rpq.q[1]);

也许这是因为我声明 RADIO_PACKET 为打包的方式。

我希望每个 RADIO_PACKET 在内部保持打包状态,但希望 GCC 根据需要在每个数组元素后添加填充,以便每个 RADIO_PACKET 从对齐地址开始。

我该怎么做?

您可以将压缩结构包裹在另一个未对齐的结构中。然后你从这个未对齐的结构中做数组。

解决方案 2 可能是,在打包结构的末尾添加虚拟成员 char[]。在这种情况下,您需要以某种方式计算它,可能是手动计算。

我也会建议你重新安排你的结构,首先放置较长的成员,最后放置 uint8_t 个成员(假设你有 16/32 位成员并且不做一些硬件映射)。

根据@Nick 在问题评论中的提示,我想我已经解决了这个问题。

我在 RADIO_PACKET 周围添加了一个 RADIO_PACKET_ALIGNED 包装器。这包括计算的填充。

然后我在RADIO_PACKET_QUEUE结构中用RADIO_PACKET_ALIGNED代替了RADIO_PACKET。

似乎有效:

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)];

既然您指定使用 GCC,您应该查看类型属性。特别是,如果您希望 RADIO_PACKETs 在 4 字节(或更宽)边界上对齐,那么您将在类型上使用 __attribute__((aligned (4)))。当应用于struct时,它描述了整体struct实例的对齐方式,而不是(直接)任何单个成员的对齐方式,因此可以将它与属性[=15=一起使用]:

typedef struct __attribute__((aligned(4), packed))
{
    uint8_t     frameLength; 
    unsigned    frameType       :3;
    uint8_t     payloadBytes;  
    uint8_t     payload[RADIO_RX_PAYLOAD_WORST];
} RADIO_PACKET;

packed 属性可防止结构元素之间的填充,但它 不会 防止结构表示中的尾部填充,这正是确保所需对齐所必需的指定类型数组的每个元素。然后您不需要在 RADIO_PACKET_QUEUE.

的声明中做任何特殊的事情

这比您提出的备选方案更简洁明了,但它是特定于 GCC 的。由于您已经是特定于 GCC 的,所以我认为这不是问题。