字节对齐
为什么字节对齐?
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问
为了提高CPU访问内存中的数据的效率在给每个数据变量分配内存空间时,需考虑地址对齐
(1)自然对齐:在给数据分配内存空间时,如果各成员数据的空间的起始地址能够被数据的长度整除,结构的总大小是最大sizeof(类型)的整数倍
typedef struct _a
{
char c1;
long i;
char c2;
double f;
}a;
typedef struct _b
{
char c1;
char c2;
long i;
double f;
}b;
结构体a的长度为24,c1一个字节,i四个字节,为了对齐,C1要补齐3个字节,C2一个字节,f八个字节,为了对齐,C2要补齐3个字节,这里一共20个字节,因为总长度要是最大sizeof(double)的倍数,所以要为24个字节
结构体b的长度为16,c1一个字节,C2一个字节,补齐2字节,i四个字节,f八个字节,一共为16个字节,也是8的倍数
(2)适当对齐:在给数据分配内存空间时,如果数据的空间的起始地址能被数据的M值整除,结构的总大小是M值的整数倍
对于不同的数据都存在一个M值
当数据的长度
当数据的长度>机器字长M=机器字长
基本数据:长度对齐
数组: 以元素的M值对齐
指针: 以4字节对齐
联合体: 成员中最大的M值对齐
结构体: 成员中最大的M值(成员排序不同,所占内存大小不一样)
struct A{
char x;
int y;
short z;
}st1;
struct B{
char x;
short z;
int y;
}st2;
结构体A总长度为12,首先看M值,最大的是y,四个字节,未超过机器字节,所以M为4,x一个字节,补齐3字节,y四个字节,z两个字节,补齐2字节,一共12字节,是M的倍数
结构体B总长度为8,M值也是为4,x一个字节,z两个个字节,补齐一个字节,y四个字节,一共8个字节,是M的倍数
从上面可以看到,结构体成员是一样的,但是顺序不一样,导致了占用的空间不一样,所以我们在定义结构体成员时,最好是按字节长度从小到大定义,可以节省空间
(3)栈上对齐:函数内的变量一般都是存在栈上的,x86平台是四字节对齐,x64平台是16字节对齐
Void test(void)
{
char c =0;
int a = 4;
char str[10]= "hello";
float f = 2.0f;
f = a+c;
}
占用空间是24字节,c一个字节,补齐3字节,a四个字节,str占10个字节,补齐2字节,f四个字节,一共24字节