You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在IAR编译器中强制结构体成员按指定字节对齐?

求助:IAR编译器下如何强制结构体成员按指定字节对齐?

最近碰到个头疼的问题,我定义了这么个结构体:

#pragma pack(4)
typedef struct {
    uint8 dataArea0[11];
    uint8 dataArea1[12];
    uint8 dataArea2[13];
    uint8 dataArea3[14];
} myStruct;

里面的几个数组长都不是2的幂,这些数组要从其他库拿数据,之后还要转成别的结构体用。结果麻烦来了:当这些结构体成员的起始地址没按4字节对齐,而且要转的结构体里有对地址对齐敏感的类型时,直接触发运行错误,搞不好程序就崩了。

我试了#pragma pack(4),但翻IAR手册才发现这个指令只是设结构体成员的最大对齐值,不是强制每个成员都按4字节对齐;data_alignment指令又只能给变量用,没法直接加在结构体成员上。想问问有没有靠谱的编译器技巧能强制结构体成员对齐?


我自己凑出来的临时解决方案

后来没办法,我自己写了个宏手动把每个数组大小向上取整到4的倍数,硬凑对齐:

#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的整数倍,每个成员的起始地址自然就按4字节对齐了,暂时解决了问题,但总觉得有点笨。


给大家看看我踩坑的错误场景

为啥对齐这么重要?给你们看我之前崩掉的代码:
我有个包含对齐敏感类型的结构体:

struct otherStruct {
    uint16 dataBuf0;
    uint32 dataBuf1;
    uint32 dataBuf2;
    uint32 dataBuf3;
    uint32 dataBuf4[10];
};

然后我把myStruct的成员强转成这个结构体指针:

myStruct* myStructInstance = (myStruct*)0x00000000; // 假设指向某个特定地址
// dataArea0是11字节,所以dataArea1的起始地址是0x0B(从0x00数11个字节到0x0A,下一个就是0x0B)
struct otherStruct* oS = (struct otherStruct*)myStructInstance->dataArea1;
// 这里给uint16类型的dataBuf0赋值,它的地址是0x0B,不是2字节对齐的,直接炸了
oS->dataBuf0 = 10;

就这一行赋值,直接触发运行错误,程序当场崩溃,查了半天才发现是对齐的锅。


后来查资料找到的IAR专属技巧

除了我手动填充的笨办法,还找到几个IAR能用的编译器技巧,分享给大家:

1. 用__attribute__((aligned(n)))修饰成员

IAR支持GNU风格的aligned属性,直接给结构体成员加这个属性就能强制对齐,比如要每个dataArea按4字节对齐:

typedef struct {
    uint8 dataArea0[11] __attribute__((aligned(4)));
    uint8 dataArea1[12] __attribute__((aligned(4)));
    uint8 dataArea2[13] __attribute__((aligned(4)));
    uint8 dataArea3[14] __attribute__((aligned(4)));
} myStruct;

这个属性会让编译器自动在成员之间加填充字节,不用自己算,比手动宏方便多了。

2. 嵌套结构体+#pragma data_alignment

如果不想用GNU属性,也可以把每个数组包成一个小结构体,然后给小结构体用#pragma data_alignment

#pragma data_alignment=4
typedef struct {
    uint8 buf[11];
} DataArea0;

#pragma data_alignment=4
typedef struct {
    uint8 buf[12];
} DataArea1;

// 同样的方式定义DataArea2和DataArea3

typedef struct {
    DataArea0 dataArea0;
    DataArea1 dataArea1;
    DataArea2 dataArea2;
    DataArea3 dataArea3;
} myStruct;

这样每个嵌套的小结构体都会被强制按4字节对齐,外层结构体的成员自然也满足对齐要求了。

3. 全局对齐配置

还可以在IAR工程设置里改全局的对齐选项(比如--data_alignment参数),直接设置所有数据的对齐方式。不过这个要谨慎,全局设置可能会让整个程序的内存占用变大,得权衡利弊再用。


内容的提问来源于stack exchange,提问作者SupAl

火山引擎 最新活动