在日常的开发工作中,时常要用到结构体的定义工作,但是结构体中数据的定义顺序是否合理直接影响了结构体所占内存的大小,所以了解C语言中内存对齐的知识十分有必要。
关于内存对齐的原则,我们首先讨论没有定义宏 #pragam pack 的情况,在该宏没有定义的情况之下,C语言中结构体的内存对齐问题主要满足一下三条原则:
1.数据成员对齐规则:struct, union的数据成员,第一个数据成员放在offset为0的地方,之后的数据成员的存储起始位置都是放在该数据成员大小的整数倍位置。如在32bit的机器上,int的大小为4,因此int存储的位置都是4的整数倍的位置开始存储。
2.结构体作为数据成员的对齐规则:在一个struct中包含另一个struct,内部struct应该以它的最大数据成员大小的整数倍开始存储。如 struct A 中包含 struct B, struct B 中包含数据成员 char, int, double,则 struct B 应该以sizeof(double)=8的整数倍为起始地址。
3.收尾工作的对齐规则:整个struct的大小,应该为最大数据成员大小的整数倍。
实例展示:
struct A
{
char a; //内存位置: [0]
double b; // 内存位置: [8]...[15]
int c; // 内存位置: [16]...[19] ---- 规则1
}; // 内存大小:sizeof(A) = (1+7) + 8 + (4+4) = 24, 补齐[20]...[23] ---- 规则3
struct B
{
int a, // 内存位置: [0]...[3]
A b, // 内存位置: [8]...[31] ---- 规则2
char c, // 内存位置: [32]
}; // 内存大小:sizeof(B) = (4+4) + 24 + (1+7) = 40, 补齐[33]...[39]
*注释:(1+7)表示该数据成员大小为1,补齐7位;(4+4)同理。
下面来解释上面提到的宏 #pragam pack的含义:
如果在代码前添加 #pragam pack(1),则 sizeof(A) = 1 + 8 + 4 = 13; sizeof(B) = 4 + 13 + 1 = 18;
那么可以猜到这个宏的含义了么?
它的意义就是,让编译器在编译的时候,给结构体按照括号中的数字,比如为i,那么就是i个字节大小来进行对齐,也就是所有的变量按照 i 的倍数的大小的起始偏移开始保存。