一般来说,编译器默认内存对齐:(以牺牲部分内存空间来提高程序性能,处理器的非内存对齐的访问需要两次,而内存对齐是一次,对齐一般来说是内存的自然边界对齐,不同类型的数据不相同)
typedef struct datal
{
int a;
double b;
union number1{
int num;
char name;
float score;
};
}
说简单点(主要是复杂的我也不会..)结构体里面每一个数据成员按照自己的对齐方式对齐,而结构中的结构按照子结构里面的数据成员中最大的对齐方式对齐。结构体分配内存按顺序分配(就是说,int和double如果反过来,结构体大小可能会不一样)
一般来说,int 是4个字节,double是8个字节,char是1个字节,float是4个字节
先说共用体union number1{
int num;
char name;
float score;
};
(呃,结构体和共用体是不一样的)
共用体是里面的数据成员每一次只有一个能够使用,内存分配的时候是按照里面数据成员内存占据最大的那个,所以这个union numberl占据4字节 (最后再说一下如果是结构体的情况)
在struct data1里面,第一个数据成员是int型,它占据4字节,他会按照自己的对齐方式在边界对齐(因为它占4自己所以他的边界应该是4的整数倍,如从1开始,从5开始,从13开始)。所以它会占据该结构体第1到第4个字节。
按顺序,第二个数据成员是double型,它占据8字节,他也是按照自己的对齐方式边界对齐(8的倍数,从第1个,第9个,等等)因为第一个被占了,而后面第9个还没有,所以它会占据该结构体的第9到第16个字节。这时候,第5个字节到第8个字节(一共四个)是闲置的内存。
再往后,是共用体union numberl(这个真心分不清是1还是l了 一和L...调试的时候差点被坑),上面说了它占4个字节,按照自己的对齐方式对齐,所以是占据该数据结构的第17个字节到第20个字节,由此,内存分配完毕。。。真的完了吗?没有,其实还有一个原则,就是分配的内存必须是成员中最大的对齐参数的整数倍,这里20不是double型8字节的整数倍,所以会多出第21到第24四个空闲内存。
由此可知道,
这个struct datal一共占据了 24 个字节的内存:
= = = = | _ _ _ _ | = = = = = = = = | = = = = | _ _ _ _
这是a
空闲内存
这是b
是共用体
空闲内存
内存对齐的三个原则:
1.每个成员按照自己的方式对齐,并能最小化长度(例如上面空闲内存不是12个而是4个)
2.复杂类型(例如这个共用体和下面说的结构体)的默认对齐方式是它最长的成员的对齐方式
3.对齐后的长度必须是成员的最大的对齐参数的整数倍
加入这里不是共用体,而是结构体(结构体每个数据成员都分配内存)例如:
ypedef struct datal
{
int a;
double b;
struct number1{
int num;
char name;
float score;
};
}
a,b的分析同上,然后说struct number1:
num 按照4字节对齐,name是1字节对齐,score是4字节对齐,这时候score和name之间有三个闲置内存。
这些加起来是28 不是8的倍数,所以最后有4字节闲置内存,一共是 32:
= = = = | _ _ _ _ | = = = = = = = = | = = = = | = _ _ _ | = = = = | _ _ _ _
这是a
空闲内存
这是b
num
name
score
空闲内存
内存对齐是有默认形式和可以调整按照多少对齐的,不同编译器好像有差异,如果想了解就查查专业资料啦