在平时做学的知识中我们直到char大小为1,short为2,int为4。
但是当在结构体中呢?
看下面一段代码:
struct A {
int a;
char b;
short c;
};
正常结构体大小算法不就应该是:4+1+2=7
但是实际运行结果为:8;
为什么会产生上面的结果,这个原因就是因为如果按照正常的大小存放,则系统大的效率会很低。
因为CPU从内存中读取数据的时候是按照一个字节一个自己读取的如果按照正常大小存取的话则会出现下面的情况
读取第一个字节char的时候,则会读取前四个字节,然后取第一个字节。
当读取第二个int的时候,就会先读取前四个字节,然后把第一位去掉,然后再读取接下来四个字节,
然后把加下来四个字节的后三位去掉,再组合到一块,资源利用率较低也很麻烦。
因此这种方法显然缺点很多,因此就产生了内存对齐的情况。
内存对齐
就是把特定类型的变量放在特定的地址上,这就需要各个变量在空间上按一定的规则排列,而不是简单地顺序排列,这就是内存对齐。
内存对齐规则
首先我们要直到几个概念:
- 数据类型自身的对齐值:就是上面交代的基本数据类型的自身对齐值。
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。 -
指定对齐值:#pragma pack (value)时的指定对齐值value。
可以使用#pragma pack (show)来显示系统自定义的值,或者这个value可以自己定义(系统默认为8,可以自己试一下) - 结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
- 数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值
这四个的第一条就是正常的自身对齐值,将这个值与指定对齐值比较,取小的就是数据的有效对齐值
然后后面三条主要是关于结构体的有效对齐值:首先找到结构体内的自身对其值最大的,然后和指定对齐值比较,两个比较小的就是结构体的有效对齐值。
了解上面四个概念之后,我们记住存放地址就行了:
存放起始地址%有效对齐值=0
主要就是这两条概念,然后我们分析一下上面的代码。
struct A {
int a; 自身对齐值为4,系统默认为8,所以有效对齐值为4,需满足存放地址%4=0,所以放到0的位置就可以了。所占位置为0,1,2,3
char b; 自身对齐值为1,系统默认为8,所以有效对齐值为1,需满足存放地址%1=0,此时位置4即满足,所占位置为4
short c; 自身对齐值为2,系统默认为8,所以有效对齐值为2,需满足存放地址%2=0,此时位置5显然不行,所以放到6的位置,所占位置6,7.
};总体占8个位置,此时结构体内最大为4,系统为8,所以结构体的有效值为4,此时8%4=0,满足条件,所以大小即为8.
如果将结构体内数据位置换一下呢?此时还是8吗?
struct B {
char b;
int a;
short c;
};
下面进行分析
struct B {
char b; 自身对齐值为1,系统默认为8,所以有效对齐值为1,需满足存放地址%1=0,此时位置0即满足,所占位置为0
int a; 自身对齐值为4,系统默认为8,所以有效对齐值为4,需满足存放地址%4=0,但是位置1,2,3都不满足,所以放在位置4,所占位置为4,5,6,7
short c; 自身对齐值为2,系统默认为8,所以有效对齐值为2,需满足存放地址%2=0,所以放到8的位置即可,所占位置8,9
};总体占10个位置,此时结构体内最大为4,系统为8,所以结构体的有效值为4,此时10%4!=0,不满足条件,所以需要调整,即取离10最近且满足%4=0,即为12,所以此时大小就变成了12
第二段代码的结构体大小12你是否看懂了呢?
主要掌握这个内存对齐规则就可以了。