3

在 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_PACKET 在内部打包。

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

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 从对齐的地址开始。

我怎样才能做到这一点?

4

3 回答 3

3

由于您指定使用 GCC,因此您应该查看类型属性。特别是,如果您希望RADIO_PACKETs 在 4 字节(或更宽)的边界上对齐,那么您将__attribute__((aligned (4)))在类型上使用。当应用于 astruct时,它描述了整体实例的对齐方式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;

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

这比您想出的替代方案更清晰、更清晰,但它是特定于 GCC 的。由于您已经是 GCC 特定的,我认为这不是问题。

于 2015-11-09T18:43:03.673 回答
2

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

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

我还建议您重新排列结构,首先放置较长的成员,uint8_t最后放置成员(假设您有 16/32 位成员并且不进行一些硬件映射)。

于 2015-11-09T17:34:25.687 回答
1

根据@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)];
于 2015-11-09T17:51:28.310 回答