内存对齐方式的原则 :
1. 成员的对齐是按声明顺序进行的;(这个很重要)==》见例1
2:在VC环境下的默认对齐值为8,PS:因为最大的非自定义类型对齐值为8。(对吗?)
3:由于对齐是按照声明顺序进行对齐的,所以这就里就会出现一些对当前成员对齐方式的影响因素:
为了方便理解,我们这边设定几个变量
A:val_self(成员自身的对齐值 如int型为4)
B:val_total(编译指示对齐值(可通过#pragma pack 进行指定,若无强制规定,则默认为8)和最大结构体成员对齐值中的较小值;)
影响因素1:首先,第一个声明的成员对齐值取val_total进行对齐;
影响因素2:(若非第一个声明的成员)看前一个声明的成员内存对齐之后的状况:
case1:若果上一个成员对齐后,所分配给其的空间剩余,且该剩余空间满足如下条件:
条件1: 该剩余空间中存在偏移值为当前成员val_self的整数倍的字节块。
条件2: 而且从该偏移算起,加上val_self仍不超出剩余空间的大小。
则当前成员填充到从该偏移算起的内存中。
例:
- struct test //val_self 为1; val_total为8
- {
- char cA; //首先按照val_total来分配内存,char占一个,剩余7个
- int iB;//上一个成员分配的空间剩余,且有偏移量为4的空间,而且4+4(int的val_self)==8,没有超过剩余空间,于是iB就填充到从偏移量为4开始的连续4个空间中。
- double dC;//
- };
case2:如果上一个成员内存分配后没有剩余空间,或者可以填充的起始偏移值加上自身的val_self超过了剩余空间大小,则当前成员仍按照val_total来分配内存。
接上例:
- struct test //val_self 为1; val_total为8
- {
- char cA; //首先按照val_total来分配内存,char占一个,剩余7个
- int iB;//上一个成员分配的空间剩余,且有偏移量为4的空间,而且4+4(int的val_self)==8,没有超过剩余空间,于是iB就填充到从偏移量为4开始的连续4个空间中。
- double dC;//<span style="color:#3333ff;">因为上一个成员iB分配完后没有剩余空间,所以自己按照val_total来分配8个空间。</span>
- };
综上,struct test的size为:8(1 + 3(空出来) + 4) + 8 == 16
********************************************************
例1:声明顺序的重要性
struct sample5
{
char a; ///1
double b; ///8
char c; ///4
int d; ///1
char e;
}; 32==》 8 + 8 + 8(1 + 3(空) + 4) + 8
struct sample5
{
double c; ///8
char a; ///1
char b; ///4
int d; ///1
char f;
}; 24 ==》8 + 8(1 + 1 + 2(空) + 4 ) + 8
以上的测试都是在VC环境下。
新加内容:(我认为这种理解更准确,摘自野火每日一题)
为了提高 CPU 的存储速度,编译器会对一些变量的起始地址做了“对齐”处理。
对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
char 偏移量必须为 sizeof(char) 即 1 的倍数
int 偏移量必须为 sizeof(int) 即 4 的倍数 (跟编译器有关,有可能是 2)
float 偏移量必须为 sizeof(float) 即 4 的倍数
double 偏移量必须为 sizeof(double) 即 8 的倍数
short 偏移量必须为 sizeof(short) 即 2 的倍数
为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
例一的解析为:
struct sample5
{
char a; ///1
double b; ///8
char c; ///4
int d; ///1
char e;
};
struct sample5
{
double c; ///8
char a; ///1
char b; ///4
int d; ///1
char f;
};
8+1+1+2(空)+4+1=17 同样需要补充7个空字节 结果为24=8+1+1+2(空)+4+1+7(空)