【问题标题】:How to get aligned array of packed structs in GCC C?如何在 GCC C 中获得对齐的打包结构数组?
【发布时间】:2015-11-09 17:04:21
【问题描述】:

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

我该怎么做?

【问题讨论】:

  • C 要求数组由 连续 对象序列组成。
  • 当出现错位问题时,为什么要将 RADIO_PACKET 声明为已打包?您确实意识到打包结构在禁止未对齐内存访问的平台上不是很有用,因为打包结构的成员未对齐?
  • @nerdfever.com 你可以先让RADIO_PACKET 不打包。你知道打包申报是什么意思吗? (提示:它告诉编译器省略任何填充)。
  • @nerdfever.com:似乎“我想要填充”和“我想要它打包”是两个根本不相容的愿望。如果您也想打包,请显式添加您自己的填充。
  • 您可以声明包装 RADIO-PACKET 的结构并保持它不对齐。然后你做这个新结构的数组。

标签: c gcc struct packed


【解决方案1】:

由于您指定使用 GCC,因此您应该查看类型属性。特别是,如果您希望 RADIO_PACKETs 在 4 字节(或更宽)的边界上对齐,那么您将在类型上使用 __attribute__((aligned (4)))。当应用于struct 时,它描述了整个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 特定的,我认为这不是问题。

【讨论】:

  • 比我的回答好多了。这就是我最初想要的。
【解决方案2】:

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

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

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

【讨论】:

  • 谢谢;赞成。我自己的答案只是一个实现。
【解决方案3】:

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

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

然后我用 RADIO_PACKET_ALIGNED 替换了 RADIO_PACKET_QUEUE 结构中的 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)];

【讨论】:

    猜你喜欢
    • 2014-11-07
    • 1970-01-01
    • 2014-07-23
    • 1970-01-01
    • 2011-02-02
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多