前言,此篇文章作者采用的是64位系统,int占4B,char占1B,而double占8B.
结构体变量的大小
有句理论是这么说的,结构体变量的大小为其所有成员所在内存大小之和。
那么问题来了,假如我有以下的这样一个结构体,此时输出它的变量大小,
struct Student{int num;char c1;double c3; };//此时用sizeof输出该结构体大小为16
哎?咱理论上讲结构体变量大小不应该是成员大小之和吗,可是我这边一个整型4字节,一个字符型1字节,一个double8字节,加起来应该是13字节才对,怎么会得到这么一个答案呢?
好,先不说这个,当我求出下面一个结构体的大小时,我震惊了。你猜怎么着,加入一个多的成员,居然不改变该变量的大小,合着我加入的成员是废物是吧。
struct Student{int num;char c1;char c2;double c3; };
OK,那这么看来,结构体变量大小存在的奥秘远不是那么简单的,很有说法啊这个东西。我上网查阅了资料得知,其实结构体大小不光是看成员大小的,结构体里存在对齐这样一个情况。
结构体对齐
结构体对齐分为两种,一种是自身的对齐方式,也就是每个变量占多少内存啦。而另一种方式,就是导致结构体变量大小奇奇怪怪的罪魁祸首,它是自然对齐。实际上,结构体变量的大小要等于结构体的自然对齐加上本身的对齐。
结构体为什么要对齐
那么结构体为什么要对齐呢。试想这么一个场景,一个结构体里面,按顺序存放了int类型一枚,char类型一枚,double类型一枚,char类型又一枚。假如我一次访问4B字节,而当我访问完int类型后,char这弟弟它只占一个字节,那很难受啊,跳过他又不行,不跳吧它又太小了恶心人,那咋办呢,系统会给它分配字节,直到什么情况呢,直到和上一个成员平齐。
struct Student{int num;char c1;double c2; };
就拿上面这个例子来说吧,当系统给这个结构体分配内存空间时
- 首先,它看到了int类型的变量num,于是给它分配了4B,也就是num的自身对齐,那么它需要自然对齐吗,不需要,因为只有他一个的时候,不讲究对齐。
- 其次,它看到了char类型变量c1,哎?c1前的变量是占4B的变量,那你c1只占一个字节,肯定不行,所以呢,它先进行了一波自然对齐,在num后面添加了3B,此时,再把后面的1B分给c1,那么此时c1就对齐成功了。
- 最后,它看到了double类型的变量c3,double本身就占8B,是一个很合适的数字(2的幂次),而且前面变量也已经对齐完毕,因此无需多言,直接分配8B,也就是c2的自身对齐。
下图是我画的内存空间布局:
OK,那包着这样的思路,我们再来看看上面奇怪的代码。
struct Student{int num;char c1;char c2;double c3; };
此时内存布局应该是如此:
可光猜肯定不行,验证下我的猜测,如果有5个char类型放在一起,那么总字节数就会从上面的16,变成24.
struct Student{int num;char c1;char c2;char c3;char c4;char c5;double dd; };
假如情况是这样,内存布局会变成:
呼呼,验证完毕,结果正确,因此咱们可以得出结论了
结构体变量大小=结构体变量本身大小+因相邻不同类型变量而产生对齐大小
结束Over