注意:该作者博客已迁移至https://buxianshan.xyz
例题:
环境:Win10+VS2017
#include<iostream>
using namespace std;
struct st1{
char a;
int b;
short c;
};
struct st2{
short c;
char a;
int b;
};
int main(){
cout<<"sizeof(st1) is "<<sizeof(st1)<<endl;
cout<<"sizeof(st2) is "<<sizeof(st2)<<endl;
return 0;
}
在不知道内存对齐之前,我会认为sizeof(st1)和sizeof(st2)都是4+1+2=7
但是,输出如下:
sizeof(st1) is 12
sizeof(st2) is 8
什么是内存对齐?
在程序员眼中内存是由一个个字节组成的。
但是CPU不这么看。CPU把内存当成是一块一块的,块的大小可以是2,4,8,16 个字节,因此CPU在读取内存的时候是一块一块进行读取的,块的大小称为(memory granularity)内存读取粒度。因此CPU在读取内存时是一块一块进行读取的。
为什么要内存对齐?
看个例子:
假设内存读取粒度(即块大小)为4。CPU要读取一个int型4字节大小的数据到寄存器中,简单分两种情况讨论:
- int数据在0,1,2,3字节
- int数据在1,2,3,4字节
第一种情况,从0字节开始读,CPU很顺利地读到了一个int数据。但是第二种情况,CPU先访问一次内存,读取0—3字节的数据进寄存器, 并再次读取4—7字节的数据进寄存器,接着把 0 字节和 5 , 6,7字节的数据剔除,合并1,2,3,4字节的数据进寄存器,这才能成功读取该int型数据。
对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。经过内存对齐之后,CPU的内存访问速度大大提升。
内存对齐的规则:
- 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是这个数据成员的自身长度 的倍数。
- 在数据成员完成各自对齐之后,结构体本身也要进行对齐,对齐将按结构体最大数据成员长度进行。
例题分析:
St1 :char +int+short
st1结构中最大数据成员长度为int,占4字节。所以结果本身按照4字节对齐,结构总大小必须为4的倍数
char占1个字节,起始偏移为0 。
int 占4个字节,所以int按4字节对齐,起始偏移必须为4的倍数,所以起始偏移为4,在char后编译器会添加3个字节的额外字节。
short占2个字节,按2字节对齐,起始偏移为8,正好是2的倍数,无须添加额外字节。但是需添加2个额外字节使结构的总大小为12 (4的倍数)。
到此内存对齐结束。St1占用了12个字节而非7个字节。oxxx|oooo|ooxx (x代表额外的字节)
同理St2:short + char + int 占用8个字节。oo|ox|oooo 。
感谢
- 李昕老师(CUMT)
- https://www.cnblogs.com/jijiji/p/4854581.html