结构体的内存对齐

来源:互联网 发布:oracle数据库全库备份 编辑:程序博客网 时间:2024/05/16 15:10

每天进步一点点


给结构体分配内存时和其它类型的数据有很大的不同,不同在哪里呢?先看下面一个例子:

#include <stdio.h>struct A{char a;int b;double c;}obj1;struct B{int b;double c;char a;}obj2;int main(){printf("%d\n", sizeof(obj1));//16printf("%d\n", sizeof(obj2));//24system("pause");return 0;}


是不是很奇怪,同样的成员,只是改变它们的顺序,结果它们的大小就不同了,为什么呢?原因是内存对齐。下面我们来详细介绍下内存对齐。

内存对齐:顾名思义,就是在储存数据时,要将它们对齐到某个位置上,具体是要对齐到哪里,这由数据的储存顺序和它本身的一些属性决定。

对齐数:数据成员需对齐到某个数字的整数倍地址处,这个数字为编译器默认的对齐数和该成员大小中的较小值。

以下编译器默认对齐数均是8。’

我们先看struct A是如何储存的:



第一个数据从偏移量为0处储存,即它不需要对齐,第二个数据需对齐,它的对齐数为自身大小与默认对齐数中的较小值,所以它的对齐数为4,即它需要对齐到地址偏移量为4的整数倍处,所以b跳过了三个字节储存,接下来储存c时,发现它的对齐数是8,而它此时的地址偏移量正好是8的整数倍,所以它紧挨着b储存,所以struct A占1+3(对齐)+4+8=16个字节。

而在改变了数据的声明顺序之后的struct B中数据时这样储存的:


其中在储存c的时候需要内存对齐,所以跳过4个字节使其对齐到对齐数(8)的整数倍处,然后紧接着储存a,但是a储存完了之后还有7个字节被空了出来,为什么呢?这里还有一个规则:在储存完所有成员后,对于整个结构体,也要对齐,它的对齐数为它所包含成员的最大对齐数(8),上面例子中,储存完a后发现其地址偏移量为17,为了使其内存对齐,所以还要给它再分配7个字节(17+7是8的整数倍),综上,我们搞清楚了struct B为什么占了24个字节(4+4(对齐)+8+1+7(整体对齐)= 24)。

为什么每个成员对齐后还要整体对齐呢?

还记得我们前面讲到结构体第一个成员不需要对齐。如果每个结构体整体之间都对齐了,那么在储存第一个结构体成员时当然就不需要对齐了。

我么也可以使用offsetof宏来确定成员的位置,它包含于头文件stddef中。原型如下、

size_t offsetof( structName, memberName);

它返回成员相对于基地址的偏移量,比如下面这个代码打印结果是8。

printf("%d\n", offsetof(struct B, c));


成于坚持,败于止步!

1 0