结构体成员对齐
前言
相关信息
不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
警告
代码编辑器的提示不可全信,要相信运行结果,如 sizeof()
参考链接
结构体成员对齐之#pragma pack(n)和__attribute__((aligned (n)))的含义和区别
结构体成员对齐规则
结构体成员对齐有2个规则,分别是 自然对齐 和 自定义对齐。
自定义对齐分为两个修饰方式:#pragma pack(n)
和 __attribute__((aligned (n)))
自然对齐规则
按照结构体成员中size最大的成员对齐
如果结构体A内还有结构体B,则相当于把结构体B的成员放到结构A中,再进行size成员对齐,这个过程可以是反复迭代的,但是结构体B需要先作内部对齐,再参与整体对齐
struct example1
{
char a;
double b;
};
struct example2
{
char c1;
int c2;
struct example1 struct1;
int e;
};
printf("%d-%d",sizeof(struct example1),sizeof(struct example2));
输出结果为:
16-32
提示
struct example1
char a
占用 1 字节- 补齐对齐:因为
double b
是 8 字节,需要在char a
后补齐 7 个字节 - 总计:1 (char a) + 7 (padding) + 8 (double b) = 16 字节
struct example2
char c1
占用 1 字节- 补齐对齐:因为
int c2
是 4 字节,需要在char c1
后补齐 3 个字节 - 1 (char c1) + 3 (padding) + 4 (int c2) = 8 字节,满足 8 字节对齐
struct example1 struct1
占用 16 字节int e
占用 4 字节- 补齐对齐:因为
struct example1 struct1
按照 8 字节对齐,需要在int e
后补齐 4 个字节 - 总计:1 (char c1) + 3 (padding) + 4 (int c2) + 16 (struct example1 struct1) + 4 (int e) + 4 (padding) = 32 字节
自定义对齐之#pragma pack(n)
结构体的成员相对于第一个成员地址的偏移量的对齐方式,需要是n的倍数
n必须是大于0的2的次方值
默认对齐规则:是自然对齐规则
如果指定的n大于结构体中最大成员的size,则按照默认对齐规则
#pragma pack()表示接下来的内容取消对齐优化,按照自然对齐规则进行对齐
#pragma pack(2)
struct example1
{
char a;
double b;
};
#pragma pack()
struct example2
{
char c1;
int c2;
struct example1 struct1;
int e;
};
printf("%d-%d",sizeof(struct example1),sizeof(struct example2));
输出结果为:
10-24
提示
struct example1
char a
占用 1 字节double b
占用 8 字节- 因为采用 2 字节对齐,所以总计 1 (char a) + 1 (padding) + 8 (double b) = 10 字节
struct example2
char c1
占用 1 字节- 补齐对齐:因为
int c2
是 4 字节,需要在char c1
后补齐 3 个字节 struct example1 struct1
占用 10 字节- 补齐对齐:因为
int e
是 4 字节,需要在struct example1 struct1
后补齐 2 个字节 int e
占用 4 字节- 总计:1 (char c1) + 3 (padding) + 4 (int c2) + 10 (struct example1 struct1) + 2 (padding) + 4 (int e) = 24 字节
自定义对齐之__attribute__((aligned (n)))
指定结构体类型的变量分配地址空间时的地址对齐方式,该结构体类型的变量在分配地址空间时,其存放的地址一定按照n字节对齐,并且其占用的空间也是n的整数倍
n必须是大于0的2的次方值
默认对齐规则:先按自然对齐规则计算总大小,然后取一个2的次方值,使得该值大于等于总大小
如果指定的n大于结构体中最大成员的size,则按照默认对齐规则
如果指定的n小于结构体中某个成员的size,则按照自然对齐规则
修饰结构体后,该结构体在后续的任何地方都将保持修饰后计算得到的值进行字节对齐
__attribute__((packed))
表示取消对齐优化
struct example1
{
char a;
double b;
}__attribute__((aligned(1024)));
struct example2
{
char c1;
int c2;
struct example1 struct1;
int e;
};
printf("%d-%d",sizeof(struct example1),sizeof(struct example2));
输出结果为:
1024-3072
提示
struct example1
struct example1
char a
占用 1 字节- 补齐对齐:因为
double b
是 8 字节,需要在char a
后补齐 7 个字节 - 因为结构体的对齐方式是 1024 字节,需要在
double b
后补齐 1008 个字节 - 总计:1 (char a) + 7 (padding) + 8 (double b) + 1008 (padding) = 1024 字节
struct example2
char c1
占用 1 字节- 补齐对齐:因为
int c2
是 4 字节,需要在char c1
后补齐 3 个字节 - 因为结构体的对齐方式是 1024 字节, 需要在
int c2
后补齐 1016 个字节 struct example1 struct1
占用 1024 字节int e
占用 4 字节- 补齐对齐:因为结构体的对齐方式是 1024 字节,需要在
int e
后补齐 1020 个字节 - 总计:1 (char c1) + 3 (padding) + 4 (int c2) + 1016 (padding) + 1024 (struct example1 struct1) + 4 (int e) + 1020 (padding) = 3072 字节