每天进步一点点!
给结构体分配内存时和其它类型的数据有很大的不同,不同在哪里呢?先看下面一个例子:
#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));//16
printf("%d\n", sizeof(obj2));//24
system("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));
成于坚持,败于止步!
【作者:果冻 http://blog.csdn.net/jelly_9】