什么是字节对齐
在计算机中,数据都是以byte作为基本单位,理论上数据存储的时候,可以以任何地址起始(数据顺序的一个一个存放),但是实际情况中,为了cpu的效率考虑,数据在存储的时候,起始地址也会存在一定的排列规律,这就是字节对齐。
准则
- 在普通位置时,存放数据的首地址,能够整除该数据类型。
举例说明:我们定义两个变量。
char a;
int b;
其中a的地址为:
b的地址为:
按照我们思维方式,变量a,b之间存储的地址应该紧挨着,但是为什么会出现这种情况,这就是字节对齐。
我们仔细一看就会发现,a的起始地址可以整除a变量的大小(char 一个字节),b的起始地址能够整除b变量的大小(short两个字节),满足准则一。
- 在结构体中,结构体变量的首地址能够被其最宽数据类型成员的大小所整除。
首先什么是最宽数据类型呢?最宽数据类型就是,在结构体中,占有空间最大的字节数。
例如:
struct Test
{
int a;
int b;
char c;
};
该结构体中的最宽数据类型为int(4字节),因此该结构体的首地址必须整除4。
我们发现,结构体中存在一些内存没有利用,如果我们的运行内存很小,避免编译器对我们进行字节对齐,我们需要主动告诉编译器,通过#pargma pack(n)
告诉编译器我们想要对齐的字节数是多少。
举例:
struct Test
{
char a;
int b;
char c;
};
默认字节对齐:大小为12
我们使用#pragma pack(n)
规定字节对齐大小
那么我们在自己设置对齐大小以后,编译器底层是如何进行处理的呢?
我们规定字节对齐大小的时候,编译器首先会判断当前字节大小与规定的字节大小的值,取一个交小的值。
例如:
上述代码字节对齐的过程:
- 首先程序的首地址一定是4的整数倍,准则二。
- 将第一个成员a,放入内存中。比较a类型的大小与设置具体数值,取较小值。min(sizeof(char),2) = 1,char类型为1个字节。则a的地址需要整除1。
- 其次存放第二个成员b。min(sizeof(int),2) = 2,所以b的首地址需要整除2,则b需要想下偏移一格。
- 接下来放入第三个成员c,方法与a类似。
但是上面的字节大小命名是7,为什么我们运行出来结果是8呢?因为还有一个注意事项。
结构体的大小必须是N = min(sizeof(最大参数类型),对齐参数)的整数倍。
还是上面的例子:
最大参数类型:int ,对齐参数 :2,因此N = min(sizeof(int),2)。所以结构体的大小需要能够整除2,当不够的时候,需要在最后补充。因此最后的结构为:
因此结果就是8