C语言的结构体对齐问题总结
1. 结构体要进行类型合理排序和字节对齐。
如:
/*排序方式1*/
typedef struct
{
uint8_t a;
int32_t c;
uint8_t b;
int32_t d;
}test_align_1;
/*排序方式2*/
typedef struct
{
uint8_t a;
uint8_t b;
int32_t c;
int32_t d;
}test_align_2;
使用编译器默认对齐方式,分别sizeof(结构体)第一种为16第二种为12。
填充默认值,保证结构体对齐:
typedef struct
{
int32_t c;
int32_t d;
uint8_t a;
uint8_t b;
int8_t res[2];
}test_align_3;
2. 编译器默认按最长字节类型对齐
#pragma pack()
typedef struct
{
int16_t a;
int8_t b;
int8_t c;
int32_t *e;
}test_align_4;
sizeof(结构体)结果是16,因为测试机是64位操作系统指针占8字节。
3. 编译器会记录最后一次#pragma pack(num)的结果
即使工程最后添加了#pragma pack(),仍然会按之前最近一次对齐方式运行,如果想确保使用编译器默认对齐方式可在结构体之前加上:#pragma pack()。具体的使用还有#pragma pack(push)和#pragma pack(pop)
4. 同一个文件是可以pack多次
如:
#include <stdio.h>
#include <stdint.h>
/*一字节对齐*/
#pragma pack(1)
typedef struct
{
uint8_t a;
int32_t c;
uint8_t b;
int32_t d;
}test_pack_5;
#pragma pack()
/*四字节对齐*/
#pragma pack(4)
typedef struct
{
uint8_t a;
int32_t c;
uint8_t b;
int32_t d;
}test_pack_6;
#pragma pack()
int main() {
int aa = sizeof(test_pack_5);
int bb = sizeof(test_pack_6);
printf("%d,%d\n",aa,bb);
return 0;
}
输出结果分别是10和16。
5. 由于对齐出现的错误
- 为了避免出错全部使用#pragma pack(1)经常是不可行的,pack在很多编辑器上对浮点型数据是无效的,这种无效并不是体现在sizeof结构体的空间大小,而是体现在float的的数据解析和赋值上。
- 对齐类出错往往出现在sizeof结构体计算内存偏移出错,出错点往往在浮点类型操作的位置,查看浮点数据的指针是否可以被4整除,来确定是否发生内存不对齐问题。
- 当结构体中存在float类型,无论是否使用了#pragma pack(1),安全起见将结构体按四字节对齐。