内存对齐方式
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
对齐方式
为什么会有内存对齐?
在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间;各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。在缺省情况下,C编译器为每一个变量或数据单元按其自然对界条件分配空间。
字,双字,和四字在自然边界上不需要在内存中对齐。(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。)无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。
某些操作双四字的指令需要内存操作数在自然边界上对齐。如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。双四字的自然边界是能够被16整除的地址。其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。
影响结构体的sizeof的因素:
1)不同的系统(如32位或16位系统):不同的系统下int等类型的长度是变化的,如对于16位系统,int的长度(字节)为2,而在32位系统下,int的长度为4;因此如果结构体中有int等类型的成员,在不同的系统中得到的sizeof值是不相同的。
2)编译器设置中的对齐方式:对齐方式的作用常常会让我们对结构体的sizeof 值感到惊讶,编译器默认都是8字节对齐。
对齐:
为了能使CPU对变量进行高效快速的访问,变量的起始地址应该具有某些特性,即所谓的“对齐”。例如对于4字节的int类型变量,其起始地址应位于4字节边界上,即起始地址能够被4整除。变量的对齐规则如下(32位系统)
理解结构体的对齐方式有点挠头,如果结构体中有结构体成员,那么这是一个递归的过程。对齐方式影响结构体成员在结构体中的偏移设编译器设定的最大对齐字节边界数为n,对于结构体中的某一成员item,一个成员的地址必须安排在成员的尺寸的整数倍地址上或者是n的整数倍地址上,取它们中的最小值,也就是它相对于结构首地址的实际字节对齐数目X应该满足以下规则:
X = min (n, sizeof (item))
实际上,1字节边界对齐也就表示了结构成员之间没有空洞。
例如,对于结构体:
struct {char a; int b} T;
当位于32位系统,n=8时:a的偏移为0,b的偏移为4,中间填充了3个字节, b 的X为4;
当位于32位系统,n=2时:a的偏移为0,b的偏移为2,中间填充了1个字节,b 的X为2;
字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;例如上面第二个结构体变量的地址空间;
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
例如1:32位系统,n=8,
结构体struct {char a; char b;} T;
struct {char a; int b;} T1;
struct {char a; int b;char c;} T2;
sizeof(T) = 2; N = 1 没有填充;
sizeof(T1) = 8; N = 4 中间填充了3字节
sizeof(T2)=12;N = 4 中间,结尾各填充了3字节
例如2:
struct S1{char a; long b;};
struct S2 {char c; struct S1 d; long long e;};
sizeof(S2)=24;
分析:
根据上面的分析sizeof(s1)=8; S2 中c和S1中的a一样,按1字节对齐,而d 是个结构,它是8个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,S1的就是4。所以,成员d就是按4字节对
齐.成员e是8个字节,它是默认按8字节对齐,和指定的一样,所以它对到8字节的边界上,这时,已经使用了12个字节了,所以又添加了4个字节的空,从第16个字节开始放置成员e.这时,长度为24,已经可以被8(成员e按8字节对齐)整除,这样一共使用了24个字节。
例如3::
Typedef struct student {
Char name[10];
Long sno;
Char sex;
Float score [4]; } STU1;
Typedef struct student {
Char name[10];
Char sex;
Long sno;
Float score [4]; } STU2;
sizeof(STU1)=10+2+4+1+3+16
sizeof(STU2)=10+2+4+16
注意:
1)对于空结构体,sizeof=1;因为必须保证结构体的每一个实例在内存中都有独一无二的地址。
2)结构体的静态成员不对结构体的大小产生影响,因为静态变量的存储位置与结构体的实例地址无关。
例如:struct {static int I;} T;
struct {char a; static int I;} T1;
sizeof(T) == 1;
sizeof(T1) == 1;
3) 某些编译器支持扩展指令设置变量或结构的对齐方式,如VC,详见MSDN (alignment of structures)
如何避免内存对齐的影响
效果:既达到提高性能的目的,又能节约一点空间。
改变缺省的对界条件: