强制结构成员对齐(使用 IAR 编译器)
Force struct member alignment (with IAR compiler)
考虑这个类型定义:
#pragma pack(4)
typedef struct
{
uint8 dataArea0[11];
uint8 dataArea1[12];
uint8 dataArea2[13];
uint8 dataArea3[14];
} myStruct;
我有一些非 2^n 大小的数组,我想从其他库中使用它们。从这些库中,这些 dataAreas 可以转换为例如结构或我需要的任何东西。当这些结构成员之一落在非 4 字节对齐的地址上并且包含对其地址对齐不满意的数据类型时,就会出现问题。
因此我想强制与 pack pragma 对齐,但这没有帮助(至少在 IAR 编译器中——来自手册:Use this pragma指令指定结构和联合成员的最大对齐。)。我还尝试使用 data_alignment 编译指示,但这似乎适用于变量而不是结构成员。
有谁知道一个很好的编译器技巧来强制结构成员对齐?
感兴趣的人可以快速链接到编译器手册:IAR AVR32 Compiler Ref
编辑:
我最终使用它作为替代方案
#define ROUND_UP_NEXT_FOUR(x) ((x + 3) & ~0x03)
typedef struct
{
uint8 dataArea0[ROUND_UP_NEXT_FOUR(11)];
uint8 dataArea1[ROUND_UP_NEXT_FOUR(12)];
uint8 dataArea2[ROUND_UP_NEXT_FOUR(13)];
uint8 dataArea3[ROUND_UP_NEXT_FOUR(14)];
} myStruct;
通过这种方式,我确定填充将发生在 4 对齐地址。
编辑2:
这个如何出错的例子:
struct otherStruct
{
uint16 dataBuf0;
uint32 dataBuf1;
uint32 dataBuf2;
uint32 dataBuf3;
uint32 dataBuf4[10];
};
myStruct* myStructInstance = 0x00000000; //some address
//address of this is 0x0B
struct otherStruct* oS = (struct otherStruct*) myStructInstance.dataArea1;
//we assign to a 2 byte variable that is
//located at address that is not 2 byte aligned -> error!
os->dataBuf0 = 10;
在这种情况下,我们会遇到运行时错误(最坏(或最好?)的情况,崩溃)。
很遗憾,IAR AVR32 编译器不支持 _Alignas
关键字。但是,当启用 IAR 语言扩展时,它支持匿名联合,这可用于强制对齐结构的各个字段。诀窍在于联合的对齐方式是其所有字段中最严格(最大)的对齐方式。因此,通过将每个字段 dataArea?
包装在一个匿名联合中,并带有一个 32 位对齐的虚拟字段,可以强制每个 dataArea?
字段对齐到 32 位。一个例子如下所示。它包括原始的匿名联合声明以及在字段数量很大时简化声明的宏魔法。
#include <stdint.h>
#define GLUE_B(x,y) x##y
#define GLUE(x,y) GLUE_B(x,y)
#define ALIGNED(FIELD, ALIGN_TYPE) union { FIELD; ALIGN_TYPE GLUE(a,__LINE__); }
#define ALIGNED32(FIELD) ALIGNED(FIELD, uint32_t)
typedef struct
{
ALIGNED(uint8_t dataArea0[11], uint32_t);
ALIGNED32(uint8_t dataArea1[12]);
union { uint8_t dataArea2[13]; uint32_t a2;};
union { uint8_t dataArea3[12]; uint32_t a3;};
} myStruct;
考虑这个类型定义:
#pragma pack(4)
typedef struct
{
uint8 dataArea0[11];
uint8 dataArea1[12];
uint8 dataArea2[13];
uint8 dataArea3[14];
} myStruct;
我有一些非 2^n 大小的数组,我想从其他库中使用它们。从这些库中,这些 dataAreas 可以转换为例如结构或我需要的任何东西。当这些结构成员之一落在非 4 字节对齐的地址上并且包含对其地址对齐不满意的数据类型时,就会出现问题。
因此我想强制与 pack pragma 对齐,但这没有帮助(至少在 IAR 编译器中——来自手册:Use this pragma指令指定结构和联合成员的最大对齐。)。我还尝试使用 data_alignment 编译指示,但这似乎适用于变量而不是结构成员。
有谁知道一个很好的编译器技巧来强制结构成员对齐?
感兴趣的人可以快速链接到编译器手册:IAR AVR32 Compiler Ref
编辑: 我最终使用它作为替代方案
#define ROUND_UP_NEXT_FOUR(x) ((x + 3) & ~0x03)
typedef struct
{
uint8 dataArea0[ROUND_UP_NEXT_FOUR(11)];
uint8 dataArea1[ROUND_UP_NEXT_FOUR(12)];
uint8 dataArea2[ROUND_UP_NEXT_FOUR(13)];
uint8 dataArea3[ROUND_UP_NEXT_FOUR(14)];
} myStruct;
通过这种方式,我确定填充将发生在 4 对齐地址。
编辑2:
这个如何出错的例子:
struct otherStruct
{
uint16 dataBuf0;
uint32 dataBuf1;
uint32 dataBuf2;
uint32 dataBuf3;
uint32 dataBuf4[10];
};
myStruct* myStructInstance = 0x00000000; //some address
//address of this is 0x0B
struct otherStruct* oS = (struct otherStruct*) myStructInstance.dataArea1;
//we assign to a 2 byte variable that is
//located at address that is not 2 byte aligned -> error!
os->dataBuf0 = 10;
在这种情况下,我们会遇到运行时错误(最坏(或最好?)的情况,崩溃)。
很遗憾,IAR AVR32 编译器不支持 _Alignas
关键字。但是,当启用 IAR 语言扩展时,它支持匿名联合,这可用于强制对齐结构的各个字段。诀窍在于联合的对齐方式是其所有字段中最严格(最大)的对齐方式。因此,通过将每个字段 dataArea?
包装在一个匿名联合中,并带有一个 32 位对齐的虚拟字段,可以强制每个 dataArea?
字段对齐到 32 位。一个例子如下所示。它包括原始的匿名联合声明以及在字段数量很大时简化声明的宏魔法。
#include <stdint.h>
#define GLUE_B(x,y) x##y
#define GLUE(x,y) GLUE_B(x,y)
#define ALIGNED(FIELD, ALIGN_TYPE) union { FIELD; ALIGN_TYPE GLUE(a,__LINE__); }
#define ALIGNED32(FIELD) ALIGNED(FIELD, uint32_t)
typedef struct
{
ALIGNED(uint8_t dataArea0[11], uint32_t);
ALIGNED32(uint8_t dataArea1[12]);
union { uint8_t dataArea2[13]; uint32_t a2;};
union { uint8_t dataArea3[12]; uint32_t a3;};
} myStruct;