内存对齐的意义
结构体中成员按照定义时的顺序依次存储在连续的内存空间。但并不是像数组那样的连续。
内存对齐计算内存地址比较方便,内存地址会非常有规律,减小了内存寻址时间。若不对齐,内存地址的变化非常没有规律。
cpu把内存当成是一块一块的。块的大小可以是2,4,8,16 个字节,因此CPU在读取内存的时候是一块一块进行读取的,块的大小称为(memory granularity)内存读取粒度。
我们再来看看为什么内存不对齐会影响读取速度?
假设CPU要读取一个4字节大小的数据到寄存器中(假设内存读取粒度是4),分两种情况讨论:
1.数据从0号自己开始
2.数据从1号字节开始(内存不对齐)
解析:当数据从0字节开始的时候,直接将0-3四个字节完全读取到寄存器,结算完成了(一遍即可)。
当数据从1字节开始的时候,问题很复杂,首先先将前4个字节读到寄存器,并再次读取4-7字节的数据进寄存器,接着把0字节,4,6,7字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器,对一个内存未对齐的寄存器进行了这么多额外操作,大大降低了CPU 的性能。
内存对齐原则:
1、第一个成员的首地址为0.
2、每个成员的首地址是自身大小的整数倍
3、结构体的总大小,为其成员中所含最大类型的整数倍。
4.任何指针在win32情况下都只占4个字节。
5,空结构体的大小为1.
例子:
以下为64位下的对齐,即最大对齐
在这里插入代struct A
{
int a; //首地址0
double b;//起始地址为8
char c;//起始地址为16
double d;//起始地址为24
float e;//起始地址为32
int f;//起始地址为36
};//总大小为40 码片
struct B
{
short b;//起始为0
char a;//起始为2
char c;//起始为3
};//总大小为4 (short类型最长,为short大小的倍数)
以上两个例子为64为下的对齐,即:最大对齐字节为8.
32位下最大对齐字节为4
#pragma pack
以使用#pragma pack来指定内存对齐的方式
在我们上面的两个例子上加上 #pragma pack(4)我们再来看看运行结果。
struct A 的大小变为了 32
如何理解?因为32为4字节对齐,我们可以把double类型看为两个4字节。
这样就好理解了。
扩展:能否使用memcmp比较两个结构体是否两同
不能用函数memcpy来判断两个结构体是否相等:memcmp函数是逐个字节进行比较的,而struct存在字节对齐,字节对齐时补的字节内容是随机的,会产生垃圾值,所以无法比较。