用一道面试题题引入
struct str1
{
char a;
int b;
float c;
double d;
};
char类型占用1个字节,int型占用4个字节,short类型占用2个字节,float占4字节,double占8字节;
那么我们可能会犯一个错误就是直接1+4+4+8=17,认为该结构体占用17个字节。这是错的。
百度一了下发现这是因为计算机中存在一种叫做内存对齐的机制导致了该结果的发生。
在计算机中通常会让CPU从内存中一次读取若干个字节的数据,而不是一次只读取一个字节的数据,这样的好处是提高了计算机的效率,然而坏处也显而易见。
假设CPU要从内存中寻找一个char型的数据和一个int型的数据,如果内存不对齐,当一次读取四个字节时,CPU找到了char型的数据后再跨越四个字节,而此时CPU的指向到了int型的中间区域,导致这个int型变量未找到,然后CPU会返回去再次寻找,直到找到该int型变量。这样不但没能提高效率,反而增加了CPU的负担。因此我们通常会在第一个char型变量后边填充一部分数据来保证每次寻址时地址都是该数据的整数倍,这样就避免了上述“错误”的发生,也就是所谓的内存对齐。
于是,我通过查阅资料总结了内存对齐的以下两个规则:
1.起始位置为该数据类型所占内存的整数倍,若不足则将不足部分填充,使其变为该数据类型所占内存的整数倍。
2.结构体所占总内存为其成员变量中所占空间最大数据类型的整数倍。
(对于32位操作系统下各数据类型的所占内存大小可以参考这篇文章:C语言数据类型与内存映射图)
假设上题中结构体变量是从0号内存开始存储,用一个字节存储了字符变量a;然后需要存储整形变量b,这时不能直接存储,因为对于b的起始位置不满足为它的数据类型所占内存的整数倍,所以应将接下来的1,2,3号内存填充占位,然后再用四个字节存储b。接下来可以直接存储float变量c,这时已经使用了1+3+4+4=12个字节内存地址。接下来存储double类型的d时,我们知道double类型需要占8字节的内存,12不是8的倍数,无法完成内存对齐,需要补充4个字节内存占位,然后再存储d,这样我们就可以计算出该结构体所占内存为12+4+8=24字节。
存储形式如下图:
char a |
int b |
b |
b |
b |
float c |
c |
c |
c |
double b |
b |
b |
b |
b |
b |
b |
b |