为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

字节对齐详解

2017-12-11 17页 doc 36KB 20阅读

用户头像

is_044822

暂无简介

举报
字节对齐详解字节对齐详解 字节对齐详解 - jack-wang - C++博客 jack-wang C++博客 首页 新随笔 联系 聚合 管理 随笔-107 评论-17 文章-0 trackbacks-0 字节对齐详解 一.什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 对齐的作用和原因...
字节对齐详解
字节对齐详解 字节对齐详解 - jack-wang - C++博客 jack-wang C++博客 首页 新随笔 联系 聚合 管理 随笔-107 评论-17 文章-0 trackbacks-0 字节对齐详解 一.什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。 二.字节对齐对程序的影响: 先让我们看几个例子吧(32bit,x86环境,gcc编译器): 设结构体如下定义: struct A { int a; char b; short c; }; struct B { char b; int a; short c; }; 现在已知32位机器上各种数据类型的长度如下: char:1(有符号无符号同) short:2(有符号无符号同) int:4(有符号无符号同) long:4(有符号无符号同) float:4 double:8 那么上面两个结构大小如何呢? 结果是: sizeof(strcut A)值为8 sizeof(struct B)的值却是12 结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一个,B也一样;按理说A,B大小应该都是7字节。 之所以出现上面的结果是因为编译器要对数据成员在空间上进行对齐。上面是按照编译器的默认设置进行对齐的结果,那么我们是不是可以改变编译器的这种默认对齐设置呢,当然可以.例如: #pragma pack (2) /*指定按2字节对齐*/ struct C { char b; int a; short c; }; #pragma pack () /*取消指定对齐,恢复缺省对齐*/ sizeof(struct C)值是8。 修改对齐值为1: #pragma pack (1) /*指定按1字节对齐*/ struct D { char b; int a; short c; }; #pragma pack () /*取消指定对齐,恢复缺省对齐*/ sizeof(struct D)值为7。 后面我们再讲解#pragma pack()的作三.编译器是按照什么样的原则进行对齐的? 先让我们看四个重要的基本概念: 1.数据类型自身的对齐值: 对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。 2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。 3.指定对齐值:#pragma pack (value)时的指定对齐值value。 4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。 有 了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是 表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数 据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数 倍,结合下面例子理解)。这样就不能理解上面的几个例子的值了。 例子分析: 分析例子B; struct B { char b; int a; short c; }; 假 设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值默认为4。第一个成员变量b的自身对齐值是1,比指定或者默认指定 对齐值4小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.第二个成员变量a,其自身对齐值为4,所以有效对齐值也为4, 所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自身对齐值为 2,所以有效对齐值也是2,可以存放在0x0008到0x0009这两个字节空间中,符合0x0008%2=0。所以从0x0000到0x0009存放的 都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求, 0x0009到0x0000=10字节,(10,2),4,0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B 共有12个字节,sizeof(struct B)=12;其实如果就这一个就来说它已将满足字节对齐了, 因为它的起始地址是0,因此肯定是对齐的,之所以在后面补充2个字节,是因为编译器为了实现结构数组的存取效率,试想如果我们定义了一个结构B的数组,那 么第一个结构起始地址是0没有问,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨着的,如果我们不把结构的大小补充为4的整数倍,那么下一 个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了,因此自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,这些已有类型的自身对齐值也是基于数组考虑的,只 是因为这些类型的长度已知了,所以他们的自身对齐值也就已知了. 同理,分析上面例子C: #pragma pack (2) /*指定按2字节对齐*/ struct C { char b; int a; short c; }; #pragma pack () /*取消指定对齐,恢复缺省对齐*/ 第 一个变量b的自身对齐值为1,指定对齐值为2,所以,其有效对齐值为1,假设C从0x0000开始,那么b存放在0x0000,符合0x0000%1= 0;第二个变量,自身对齐值为4,指定对齐值为2,所以有效对齐值为2,所以顺序存放在0x0002、0x0003、0x0004、0x0005四个连续 字节中,符合0x0002%2=0。第三个变量c的自身对齐值为2,所以有效对齐值为2,顺序存放 在0x0006、0x0007中,符合 0x0006%2=0。所以从0x0000到0x00007共八字节存放的是C的变量。又C的自身对齐值为4, 所以C的有效对齐值为2。又8%2=0,C 只占用0x0000到0x0007的八个字节。所以sizeof(struct C)=8. 四.如何修改编译器的默认对齐值? 1.在VC IDE中,可以这样修改:[Project]|[Settings],c/c++选项卡Category的Code Generation选项的Struct Member Alignment中修改,默认是8字节。 2.在编码时,可以这样动态修改:#pragma pack .注意:是pragma而不是progma. 五.针对字节对齐,我们在编程中如何考虑? 如果在编程的时候要考虑节约空间的话,那么我们只需要假定结构的首地址是0,然后各个变量按照上面的原则进行排列即可,基本的原则就是把结构中的变量按照 类型大小从小到大声明,尽量减少中间的填补空间.还有一种就是为了以空间换取时间的效率,我们显示的进行填补空间进行对齐,比如:有一种使用空间换时间做 法是显式的插入reserved成员: struct A{ char a; char reserved[3];//使用空间换时间 int b; } reserved成员对我们的程序没有什么意义,它只是起到填补空间以达到字节对齐的目的,当然即使不加这个成员通常编译器也会给我们自动填补对齐,我们自己加上它只是起到显式的提醒作用. 六.字节对齐可能带来的隐患: 代码中关于对齐的隐患,很多是隐式的。比如在强制类型转换的时候。例如: unsigned int i = 0x12345678; unsigned char *p=NULL; unsigned short *p1=NULL; p=&i; *p=0x00; p1=(unsigned short *)(p+1); *p1=0x0000; 最后两句代码,从奇数边界去访问unsignedshort型变量,显然不符合对齐的。 在x86上,类似的操作只会影响效率,但是在MIPS或者sparc上,可能就是一个error,因为它们要求必须字节对齐. 七.如何查找与字节对齐方面的问如果出现对齐或者赋值问题首先查看 1. 编译器的big little端设置 2. 看这种体系本身是否支持非对齐访问 3. 如果支持看设置了对齐与否,如果没有则看访问时需要加某些特殊的修饰来标志其特殊访问操作。 八.相关文章:转自 ARM下的对齐处理 from DUI0067D_ADS1_2_CompLib 3.13 type qulifiers 有部分摘自ARM编译器文档对齐部分 对齐的使用: 1.__align(num) 这个用于修改最高级别对象的字节边界。在汇编中使用LDRD或者STRD时 就要用到此命令__align(8)进行修饰限制。来保证数据对象是相应对齐。 这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节 对齐,但是不能让4字节的对象2字节对齐。 __align是存储类修改,他只修饰最高级类型对象不能用于结构或者函数对象。 2.__packed __packed是进行一字节对齐 1.不能对packed的对象进行对齐 2.所有对象的读写访问都进行非对齐访问 3.float及包含float的结构联合及未用__packed的对象将不能字节对齐 4.__packed对局部整形变量无影响 5.强制由unpacked对象向packed对象转化是未定义,整形指针可以合法定 义为packed。 __packed int* p; //__packed int 则没有意义 6.对齐或非对齐读写访问带来问题 __packed struct STRUCT_TEST { char a; int b; char c; } ; //定义如下结构此时b的起始地址一定是不对齐的 //在栈中访问b可能有问题,因为栈上数据肯定是对齐访问[from CL] //将下面变量定义成全局静态不在栈上 static char* p; static struct STRUCT_TEST a; void Main() { __packed int* q; //此时定义成__packed来修饰当前q指向为非对齐的数据地址下面的访问则可以 p = (char*)&a; q = (int*)(p+1); *q = 0x87654321; /* 得到赋值的汇编指令很清楚 ldr r5,0x20001590 ; = #0x12345678 [0xe1a00005] mov r0,r5 [0xeb0000b0] bl __rt_uwrite4 //在此处调用一个写4byte的操作函数 [0xe5c10000] strb r0,[r1,#0] //函数进行4次strb操作然后返回保证了数据正确的访问 [0xe1a02420] mov r2,r0,lsr #8 [0xe5c12001] strb r2,[r1,#1] [0xe1a02820] mov r2,r0,lsr #16 [0xe5c12002] strb r2,[r1,#2] [0xe1a02c20] mov r2,r0,lsr #24 [0xe5c12003] strb r2,[r1,#3] [0xe1a0f00e] mov pc,r14 */ /* 如果q没有加__packed修饰则汇编出来指令是这样直接会导致奇地址处访问失败 [0xe59f2018] ldr r2,0x20001594 ; = #0x87654321 [0xe5812000] str r2,[r1,#0] */ //这样可以很清楚的看到非对齐访问是如何产生错误的 //以及如何消除非对齐访问带来问题 //也可以看到非对齐访问和对齐访问的指令差异导致效率问题 } 本文来自CSDN博客,转载请标明出处: posted on 2010-03-17 15:55 小王 阅读(107) 评论(0) 编辑 收藏 引用 所属分类: c++ 程序基础 盛大Bambook程序达人赛 IT新闻: ? 微软和谷歌在零日漏洞发布方面出现冲突 ? 2011 CES大展前瞻:微软将推Windows TV ? 消息称高通将以35亿美元收购Atheros通信 ? 摩托解决部CEO:今年将向股东派发红利 ? 联通开通5国家漫游套餐:不限量日封顶150元 推荐职位: 北京网路时代诚聘C++开发工程师 博客园 博问 IT新闻 学英语 C++程序员招聘 标题请输入标题 姓名请输入你的姓名 主页 请输入验证码 验证码* 内容(提交失败后,可以通过“恢复上次提交”恢复刚刚提交的内容) 请输入评论内容 Remember Me? 登录 使用高级评论 新用户注册 返回页首 恢复上次提交 [使用Ctrl+Enter键可以直接提交] 每天10分钟,轻松学英语 推荐职位: ? .NET 开发工程师 (北京世纪英博) ? .NET 高级软件工程师 (苏州统购信息) ? 网站运营人员(苏州统购信息) ? .NET开发工程师(北京网路时代) ? [急聘].NET/Web开发工程师(武汉百纳信息技术) ? .NET开发工程师(上海盖世网络) ? Windows底层开发工程师(C++)(北京网路时代) ? 中高级.NET程序员(沪江网) 博客园首页随笔: ? 云计算-从基础到应用架构系列-云计算的概念 ? Android 情景模式的设置 ? Delphi XE的RTTI增强,动态Hook某些内部事件 ? 同样是程序员,不小心发现了自己的优点,在于工作上10来年都保持【积极主动】 的心态 ? 月份信息二维坐标图绘制---(绘制箭头完美算法)续II 知识库: ? 坐标高速插入,移动和查询算法 ? 在MVC2.0使用Lodop为WEB打印提出完美解决方案 ? PHP最佳实践 ? 关于程序成本的讨论 ? C#不为人知的秘密-缓冲区溢出 相关文章: 几个基本的库函数,备忘 代码自动生成-宏带来的奇技淫巧 VS2005/2008 warning C4251 needs to have dll-interface 字节对齐详解 Visual C++2010的c++语言四大新特性 今天工作中突然提到了stdcall,我都有些忘了,差点被主管问倒,再温习一遍 最快速度找到内存泄漏 网站导航: 博客园 IT新闻 博客园个人主页 BlogJava 博客生活 IT博客网 PHP博 客 博客园社区 管理 最简洁阅读版式: 字节对齐详解 日一二三四五六 28123456 78910111213 14151617181920 21222324252627 28293031123 45678910 常用链接我的随笔 我的评论 我参与的随笔 留言簿(1)给我留言 查看公开留言 查看私人留言 随笔分类(103)C#专栏 c++ 程序设计基础(7) DB(3) Java专栏(2) linux专栏(9) STL、Boost(6) VC专栏(7) Web开发(1) 操作系统(1) 多核编程(3) 分布式系统(4) 汇编(1) 开源项目(2) 其他(9) 软件工程(1) 设计模式(5) 算法与数据结构(1) 网络通讯(15) 游戏服务器端开发(15) 游戏引擎(11) 随笔档案(107)2010年12月 (1) 2010年11月 (7) 2010年10月 (7) 2010年9月 (2) 2010年8月 (2) 2010年7月 (3) 2010年6月 (3) 2010年5月 (1) 2010年4月 (4) 2010年3月 (6) 2010年2月 (12) 2010年1月 (22) 2009年12月 (1) 2009年11月 (7) 2009年8月 (5) 2009年6月 (4) 2009年2月 (4) 2009年1月 (15) 2008年10月 (1) Linuxchinaunix 游戏开发金庆 云风 综合Intel λ-calculus 周伟明 最新随笔1. 成为一名优秀程序员所需要知道的那些事 2. error LNK2019: 无法解析的外部符号 __imp___CrtDbgReportW 3. vs2005抱怨找不着libc.lib的问题 4. 曾经有个游戏叫《传奇》 5. 用 Eclipse 平台进行 C/C++ 开发 6. 开发笔记:在Ubuntu下安装JDK 6和Eclipse 7. 编译openfetion2 8. 编译Openfetion 9. Ubuntu9.10 VI下方向键变成ABCD的解决办法 10. 程序员必须知道的SQLSERVER数据库优化技巧 搜索 最新随笔1. 成为一名优秀程序员所需要知道的那些事 2. error LNK2019: 无法解析的外部符号 __imp___CrtDbgReportW 3. vs2005抱怨找不着libc.lib的问题 4. 曾经有个游戏叫《传奇》 5. 用 Eclipse 平台进行 C/C++ 开发 6. 开发笔记:在Ubuntu下安装JDK 6和Eclipse 7. 编译openfetion2 8. 编译Openfetion 9. Ubuntu9.10 VI下方向键变成ABCD的解决办法 10. 程序员必须知道的SQLSERVER数据库优化技巧 最新评论 1. re: 曾经有个游戏叫《传奇》 那段美好的回忆呀 --yugi 2. re: 公司散伙啦。杯具~反思~ 真是杯具~ --2009 3. re: 找不到d3dx9_38.dll[未登录] 找不到怎么办 --cc 4. re: vs2005环境下编译CEGUI 0.6.0 乱 --aaa 5. re: 代码自动生成-宏带来的奇技淫巧 - -! 路过,你懂的 --Kevin Lynx 阅读排行榜1. vs2005环境下编译CEGUI 0.6.0(1202) 2. 号称是目标软件的服务器架构(转载的,不关我事哦,图片就不发了,懒)(1100) 3. 网游服务器通信架构的设计(817) 4. 谷歌技术“三宝”之一的Google文件系统和Kosmos 文件系统(578) 5. 网游服务器架构的评论排行榜1. kosmix,又一个开源的类似GFS的分布式文件系统(3) 2. 公司散伙啦。杯具~反思~(3) 3. 没有找到MSVCR90.dll,因此这个应用程序未能启动,重新安装应用程序可能会修复此 问题(1) 4. 曾经有个游戏叫《传奇》(1) 5. 找不到d3dx9_38.dll(1) Powered by: 博客园 模板提供:沪江博客 Copyright ?2011 小王
/
本文档为【字节对齐详解】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索