




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
内存对齐详解文章1一、内存对齐的原因大部分的参考资料都是如是说的:1、 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。2、 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。二、对齐规则每个特定平台上的编译器都有自己的默认“对齐系数”也叫对齐模数)。程序员可以通过预编译命令#pragmapack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的"对齐系数”。规则1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragmapack指定的数值和这个数据成员自身长度中,比较小的那个进行。规则2:结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragmapack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。规则3:结合1、2颗推断:当#pragmapack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。三、试验我们通过一系列例子的详细说明来证明这个规则吧!我试验用的编译器包括GCC3.4.2和VC6.0的C编译器,平台为WindowsXP+Sp2。我们将用典型的struct对齐来说明。首先我们定义一个struct:#pragmapack(n)/*n=1,2,4,8,16*/structtest_t{inta;charb;shortc;chard;};#pragmapack(n)首先我们首先确认在试验平台上的各个类型的size,经验证两个编译器的输出均为:sizeof(char)=1sizeof(short)=2sizeof(int)=4我们的试验过程如下:通过#pragmapack(n)改变"对齐系数",然后察看sizeof(structtest_t)的值。1、 1字节对齐(#pragmapack(1))输出结果:sizeof(structtest_t)=8[两个编译器输出一致]分析过程:成员数据对齐#pragmapack(1)structtest_t{inta;/*长度4<1按1对齐;起始offset=00%1=0;存放位置区间[0,3]*/charb;/*长度1=1按1对齐;起始offset=44%1=0;存放位置区间[4]*/shortc;/*长度2>1按1对齐;起始offset=55%1=0;存放位置区间[5,6]*/chard;/*长度1=1按1对齐;起始offset=77%1=0;存放位置区间[7]*/};#pragmapack()成员总大小=8整体对齐整体对齐系数=min((max(int,short,char),1)=1整体大小(size)=$(成员总大小)按$(整体对齐系数)圆整=8/*8%1=0*/[注1]2、 2字节对齐(#pragmapack(2))输出结果:sizeof(structtest_t)=10[两个编译器输出一致]分析过程:1)成员数据对齐#pragmapack(2)structtest_t{inta;/*长度4>2按2对齐;起始offset=00%2=0;存放位置区间[0,3]*/charb;/*长度1<2按1对齐;起始offset=44%1=0;存放位置区间[4]*/shortc;/*长度2=2按2对齐;起始offset=66%2=0;存放位置区间[6,7]*/chard;/*长度1<2按1对齐;起始offset=88%1=0;存放位置区间[8]*/};#pragmapack()成员总大小=92)整体对齐整体对齐系数=min((max(int,short,char),2)=2整体大小(size)=$(成员总大小)按$(整体对齐系数)圆整=10/*10%2=0*/3、4字节对齐(#pragmapack(4))输出结果:sizeof(structtest_t)=12[两个编译器输出一致]分析过程:1)成员数据对齐#pragmapack(4)structtest_t{
inta;/*长度4=4按4对齐;起始offset=00%4=0;存放位置区间[0,3]*/charb;/*长度1<4按1对齐;起始offset=44%1=0;存放位置区间[4]*/shortc;/*长度2<4按2对齐;起始offset=66%2=0;存放位置区间[6,7]*/chard;/*长度1<4按1对齐;起始offset=88%1=0;存放位置区间[8]*/};#pragmapack()2)成员总大小=92)成员总大小=9整体对齐系数=min((max(int,short,char),4)=4整体对齐系数=min((max(int,short,char),4)=4整体大小(size)=$(成员总大小)按$(整体对齐系数)圆整=12/*12%4=0*/4、8字节对齐(#pragmapack(8))输出结果:sizeof(structtest_t)=12[两个编译器输出一致]分析过程:1)成员数据对齐#pragmapack(8)structtest_t{inta;/*长度4<8按4对齐;起始offset=00%4=0;存放位置区间[0,3]*/charb;/*长度1<8按1对齐;起始offset=44%1=0;存放位置区间[4]*/shortc;/*长度2<8按2对齐;起始offset=66%2=0;存放位置区间[6,7]*/chard;/*长度1<8按1对齐;起始offset=88%1=0;存放位置区间[8]*/};#pragmapack()成员总大小=92)整体对齐整体对齐系数=min((max(int,short,char),8)=4整体大小(size)=$(成员总大小)按$(整体对齐系数)圆整=12/*12%4=0*/5、16字节对(#pragmapack(16))输出结果:sizeof(structtest_t)=12[两个编译器输出一致]分析过程:1)成员数据对齐#pragmapack(16)structtest_t{inta;/*长度4<16按4对齐;起始offset=00%4=0;存放位置区间[0,3]*/charb;/*长度1<16按1对齐;起始offset=44%1=0;存放位置区间[4]*/shortc;/*长度2<16按2对齐;起始offset=66%2=0;存放位置区间[6,7]*/chard;/*长度1<16按1对齐;起始offset=88%1=0;存放位置区间[8]*/};#pragmapack()成员总大小=9整体对齐系数=min((max(int,short,char),16)=4整体大小(size)=$(成员总大小)按$(整体对齐系数)圆整=12/*12%4=0*/四、结论8字节和16字节对齐试验证明了"规则"的第3点:"当#pragmapack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果”。另外内存对齐是个很复杂的东西,上面所说的在有些时候也可能不正确。呵呵A_A[注1]什么是“圆整”?举例说明:如上面的8字节对齐中的"整体对齐”,整体大小=9按4圆整=12圆整的过程:从9开始每次加一,看是否能被4整除,这里9,10,11均不能被4整除,到12时可以,则圆整结束。程序校验(环境VC++6.0)intmain(){inta;charb;shortc;chard;//ox0012ff1cox0012ff18ox0012ff14ox0012ff10printf("ox%08x",&a);printf("ox%08x",&b);printf("ox%08x",&c);printf("ox%08x\n",&d);文章2此页面可以通过在dev_c++运行,并通过小量的更改在其他IDE下运行.摘要:本文描述了内存对齐的各种概念和内存管理的其他知识点,应用相应的程序示例进行解释.备注:本文资料收集于网络并通过作者整理.此篇不考虑继承和虚函数虚表问题.此类问题分析详见下个版本.whatandwhy什么是字节对齐,为什么要对齐?现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐.对齐的作用和原因?各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台要求对齐数据存放进行对齐,会在存取效率上带来损失.比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据.显然在读取效率上下降很多.4个重要概念数据类型自身的对齐值:对于char型数据,其自身对齐值为1;对于short型为2;对于int,float,double类型,其自身对齐值为4单位字节.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值.指定对齐值:#pragmapack(value)时的指定对齐值value.数据成员,结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值.有效对齐值拓展有效对齐值n是最终用来决定数据存放地址方式的值.有效对齐n,就是表示对齐在n上,也就是说该数据的"存放起始地址%n=0".而数据结构中的数据变量都是按定义的先后顺序来排放的.第一个数据变量的起始地址就是数据结构的起始地址.结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍,结合下面例子理解).#endif#include<iostream>usingstd::cout;usingstd::endl;voidnewSet();voidnewSet_P();typedefstruct{intid;doubleweight;floatheight;}ZX;//4:[0] [3]〃8:[7].•…[15] 原则1〃4:[16]..[19],总长要为8的整数倍,补齐[20]...[23] 原则3typedefstruct{charname[2];intid;//2:[0],[1]//4:[4]...[7] 原则1doublescore;shortgrade;ZXb;}ZX_1;//8:[8] [15]//2:[16],[17]〃24:[24]......[47] 原则2intmain(){ZX_1a;cout<<sizeof(ZX_1)<<""<<sizeof(ZX)<<endl;cout<<"改变顺序的对比:"<<endl;newSet();cout<<"利用编译指令#pragmapack(value)进行对比:"<<endl;newSet_P();system("pause");return0;#if0输出为:sizeof(ZX_1)=48,sizeof(ZX)=24调整数据成员的结构就改变了结构的sizeof(value);例如:把ZX中的doubleweight;提到intid;前面的话就得到sizeof(ZX)=16;#endif}voidnewSet(){typedefstruct{inta;charb;shortc;}NEW_1;typedefstruct{charb;inta;shortc;}NEW_2;typedefstruct{inta;charb;shortc;}NEW_0;struct{shortc;charb;inta;}NEW_3;cout<<sizeof(NEW_1)<<endl;cout<<sizeof(NEW_2)<<endl;cout<<sizeof(NEW_3)<<endl;}voidnewSet_P(){#pragmapack(1)typedefstruct{inta;charb;shortc;}NEW_1;typedefstruct{charb;inta;shortc;}NEW_2;typedefstruct{inta;charb;shortc;}NEW_0;struct{shortc;charb;inta;}NEW_3;cout<<sizeof(NEW_1)<<endl;cout<<sizeof(NEW_2)<<endl;cout<<sizeof(NEW_3)<<endl;#pragmapack()}#if0计算sizeof(value)必需遵循的原则数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始.(如int在32位机为4字节,则要从4的整数倍地址开始存储)结构体作为成员对齐规则:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(structa里存有structb,b里有char,int,double等元素,那b应该从8的整数倍开始存储.)收尾工作:结构体的总大小即sizeof的结果.必须是其内部最大成员的整数倍.不足的要补齐.在考虑内存对齐时的编程技巧在编程的时候要考虑节约空间的话,那么我们只需要假定结构的首地址是0,然后各个变量按照上面的原则进行排列即可,基本的原则就是把结构中的变量按照类型大小从小到大声明,尽量减少中间的填补空间.还有一种就是为了以空间换取时间的效率,我们显示的进行填补空间进行对齐比如:有一种使用空间换时间做法是显式的插入reserved成员structA{chara;charreserved[3];//使用空间换时间intb;}reserved成员对我们的程序没有什么意义,它只是起到填补空间以达到字节对齐的目的,当然即使不加这个成员通常编译器也会给我们自动填补对齐,我们自己加上它只是起到显式的提醒作用.总结总之,内存对齐方式就是把数据类型中的数据成员一个一个的排在内存中,并且按照上面所述的原则就行计算sizeof(type)的值.补充:1.对齐方式设置在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间(自然对齐:结构中对齐要求最严格的作为对齐字节数,对齐要求最严格即占用空间最大的,例如double比int要求严格)。一般地,可以通过下面的方法来改变缺省的对界条件:•使用伪指令#pragmapack(n),C编译器将按照n个字节对齐。•使用伪指令#pragmapack(),取消自定义字节对齐方式。另外,还有如下的一种方式:• —attribute((aligned(n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。attribute— ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。2.计算偏移-offsetof宏定义#defineoffsetof(s,m)(size_t)&(((s*)0)->m)s是一个结构名,它有一个名为m的成员(s和m是宏offsetof的形参,它实际是返回结构s的成员m的偏移地址.(s*)0是骗编译器说有一个指向类(或结构)s的指针,其地址值0&((s*)0)->m是要取得类s中成员变量m的地址.因基址为0,这时m的地址当然就是m在s中的偏移最后转换size_t型,即unsignedint。#defineoffsetof(TYPE,MEMBER)((size_t)&((
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 市场竞争对手分析数据表
- 智能制造技术生产流水线操作手册
- 三农村公共服务智能化提升方案
- 交通物流行业绿色运输策略方案
- 物流行业无人配送技术推广方案
- 附件3医院护类人员年终理论考试500题练习卷附答案
- 乡村绿化美化服务方案
- 三农产品电商助力农业新兴业态培育与发展方案
- 餐饮行业餐饮企业营销策略及实施方案
- 高效率办公软件使用简明教程
- 《中国高血压临床实践指南2024》解读
- 2024年度国家铁路局信息中心面向社会公开招聘工作人员3人易考易错模拟试题(共500题)试卷后附参考答案
- 2024北京海淀区初三一模物理试题及参考答案
- 装饰画教学课件
- 工余安健环管理标准
- 附件1:肿瘤防治中心评审实施细则2024年修订版
- 2024-2030年中国自动自攻铆钉行业市场发展趋势与前景展望战略分析报告
- DL∕T 868-2014 焊接工艺评定规程
- 2024年北京中考语文试题及答案
- 幼儿园足球课程实施方案(18篇)
- 【地理】河南省洛阳市强基联盟2023-2024学年高一下学期3月联考试题(解析版)
评论
0/150
提交评论