以前单纯以为结构体 共用体的内存大小只需要算出每个成员的内存大小求总和就是了,慢慢才知道并不是这样。
那么为什么会出现内存对齐呢,
大部分的参考资料都是如是说的:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
那让我们来弄清楚他的对齐规则吧
例:
struct s
{
doiuble a;
int b;
char c;
float d;
};
sizeof(struct s)是多少呢?
其实并不是简单的8+4+1+4=17,而是24。为什么呢?
这里最大的基本类型是double,为8字节,所以该结构体是以8字节对齐的,所以是24.
union s
{
int a;
char b[10];
};
该共用体内存大小为12
最大基本类型是int,而长度为数组b决定的,为10,10不是4的倍数,进行对齐后为12
union s
{
char a;
char b[3];
};
内存为3,基本类型为char,长度由b数组决定
再来看下面这三种情况
struct s1
{
int a;
char b;
char c;
};
struct s2
{
char a;
char b;
int c;
};
struct s3
{
char a;
int b;
char c;
};
这三种情况结果一样么,你可能会说,都是12,然而并不是这样的struct s1,struct s2是8,然而struct s3是12,为什么呢
三种情况最大基本类型都是int,分配存储空间的时候,编译器知道是以4对齐的,第三种分配时,因为要考虑对齐,所以a得到的存储空间其实是4,b是4,c是4,所以是12
但是前两种没有必要,只需要给两个char型的分配4就够用了,所以是8
struct s
{
char a;
int b;
char c;
};
union s2
{
struct s a;
double b;
};
稍微复杂一点的来了,s2存储长度是多少呢
最大基本类型是double,长度取决于a,为12,而要与8对齐,所以这个共用体的存储空间是16
struct s
{
int a;
long b;
double c;
float d;
char e;
short f;
};
这个又占多少呢
答案是24
最长基本类型是double,a b各自分配4,c分配8,d e f加起来是7,所以扔给他们一个8就可以了,所以4+4+8+8=24
struct s
{
int a;
long b;
double c;
float d;
char e[3];
short f;
};
这个又是多少呢
这里只变了char数组e[3],那么现在d+e+f所需要的存储空间变成了9,8就不够了,现在就需要进行补齐。d分配4,e分配4,f分配8
4+4+8+4+4+8=32
内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不应该再透明了。