C语言的结构体对齐问题总结

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;
}

输出结果分别是1016

5. 由于对齐出现的错误

  • 为了避免出错全部使用#pragma pack(1)经常是不可行的,pack在很多编辑器上对浮点型数据是无效的,这种无效并不是体现在sizeof结构体的空间大小,而是体现在float的的数据解析和赋值上。
  • 对齐类出错往往出现在sizeof结构体计算内存偏移出错,出错点往往在浮点类型操作的位置,查看浮点数据的指针是否可以被4整除,来确定是否发生内存不对齐问题。
  • 当结构体中存在float类型,无论是否使用了#pragma pack(1),安全起见将结构体按四字节对齐。
上一篇:zblog robots.txt的正确写法,php版本


下一篇:深入探索C语言struct的用法