结构体的大小取决于每个成员的大小以及他们的地址对齐要求,由于地址需要对齐,因此结构体内部一般都存在填充现象。
拓展:
变量的地址需要对齐意味着:在内存中开辟一块空间(即变量)的时候,并不是随便搞一块适当大小的内存就可以了,我们对这块内存的地址是有要求的,比如int型或者double型数据的地址必须是4的整数倍,再如short型数据的地址必须是2的整数倍等等,这些要求,就是所谓的地址对齐。
为了符合人类口腔生理结构,方便描述,我们把“int型数据的地址必须至少是4的整数倍”这句又长又臭的话简化为“int型数据的m值等于4”。这个m值,指的就是对变量地址的要求。每一个变量都不能随便放的,因此实际上每一个变量都有其m值。
关键是,为什么要对齐呢?用一幅图来说明这个问题:
每一款不同的处理器,存取内存数据都会有不同的策略,如果是32位的CPU,一般来讲他在存取内存数据的时候,每次至少存取4个字节(即32位),也就是按4字节对齐来存取的。换个角度讲:CPU有这个能力,他能一次存取4个字节。
接下来我们可以想到,为了更高效地读取数据,编译器会尽可能地将变量塞进一个4字节单元里面,因为这样最省时间。如果变量比较大,4个字节放不下,则编译器会尽可能地将变量塞进两个4字节单元里面,反正一句话:两个坑能装得下的就绝不用三个坑。这就是为什么变量的地址要对齐的最根本原因。
以一个double型变量为例,double型变量占8个字节,以下是地址未对齐时的情况:
可见,如果对一个double型数据的地址不作要求,那么CPU就有可能为此付出代价:需要三个指令周期才能将区区8个字节搬到家里来,这显然很不环保,环保的做法是:令其地址至少是4的整数倍(即4字节对齐),则情况变成:
可以总结出一套这样的规律(假设是32位系统):
1,如果变量的尺寸小于4字节,那么该变量的m值等于变量的长度。
2,如果变量的尺寸大于等于4字节,则一律按4字节对齐。
3,如果变量的m值被人为调整过,则以调整后的m值为准。
强调一点:一个变量的m值规定了这个变量的地址的最小倍数,同时也规定了这个变量的大小至少是这个m值的倍数。m值不是这个变量的大小。
结构体本身也是一个变量,结构体变量的m值取决于其成员中m值最大的那个。以上面的结构体为例:
struct node
{
short a;
double b;
char c;
}x;
按照上述总结出来的规律可知:
ma = 2
mb = 4
mc = 1
结构体x的m值取最大值:mx = max{2, 4, 1},答案自然是:
mx = 4