如何在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




