RealView MDK中结构体存储方式

[复制链接]
2927|2
 楼主| sword1013 发表于 2008-4-2 08:48 | 显示全部楼层 |阅读模式
对于RISC机器来说,对齐访问可以提高效率。ARM是RISC机器,因此在多数情况下它以对齐方式访问,即访问的地址一般是4或2的倍数。但在某些特殊应用上,对齐访问可能会带来麻烦。下面笔者以自身经历来说明有些情况是不允许对齐访问的,好在强大的MDK早就意料到这些特殊应用,并有相应的对策。<br /><br />下面举例说明结构以对齐方式和非对齐方式存储的差别。<br /><br />下面以三种不同的方式定义了结构体foo,见表一。其中第一种是常用的(默认情况)定义方式。第二种和第三种方式均以压缩方式存储,以非对齐方式访问。其中第二种方式关键字__packed修饰整个结构体,表明整个结构体以压缩方式存储;第三种方式关键字__packed修饰结构体中的某个域,被修饰的域以压缩的方式存储。而其它部分则采用非压缩方式。当然在示例结构体foo中,后两种定义方法达到的效果一样。<br /><br />在第一种方式中,结构体成员one占用两个字节;成员two占用两个字节;成员three占用4个字节;成员four占用4个字节。&nbsp;而在第二种和第三种方式中它们分别占用1个字节、两个字节、一个字节、4个字节。如果读者看到这还不是很清楚的话,那么请看其对应的汇编代码,见表二。<br /><br />表一&nbsp;三种定义结构体方式对比<br /><br />非压缩方式存储(对齐访问)<br />&nbsp;将整个结构体以压缩方式存储<br />&nbsp;将结构体中的部分成员压缩方式存储<br />&nbsp;<br />Struct&nbsp;foo<br /><br />{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;one;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;short&nbsp;two;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;three;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;four;<br /><br />}&nbsp;c;<br />&nbsp;__packed&nbsp;struct&nbsp;foo<br /><br />{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;one;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;short&nbsp;two;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;three;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;four;<br /><br />}&nbsp;c;<br />&nbsp;struct&nbsp;foo<br /><br />{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;one;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;__packed&nbsp;short&nbsp;two;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;three;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;four;<br /><br />}&nbsp;c;<br />&nbsp;<br /><br />&nbsp;<br /><br />表二&nbsp;三种定义结构体方式对应用汇编代码<br /><br />非压缩方式存储(对齐方式)<br />&nbsp;将整个结构体以压缩方式存储<br />&nbsp;将结构体中的部分成员压缩方式存储<br />&nbsp;<br />;&nbsp;r0&nbsp;包含了结构体c的首地址。<br /><br />&nbsp;<br /><br />LDRB&nbsp;&nbsp;&nbsp;&nbsp;r1,&nbsp;[r0,&nbsp;#0]<br /><br />LDRSH&nbsp;&nbsp;&nbsp;r2,&nbsp;[r0,&nbsp;#2]<br /><br />LDRB&nbsp;&nbsp;&nbsp;&nbsp;r3,&nbsp;[r0,&nbsp;#4]<br /><br />LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r12,&nbsp;[r0,&nbsp;#8]<br />&nbsp;;&nbsp;r0&nbsp;包含了结构体c的首地址。<br /><br />&nbsp;<br /><br />;&nbsp;char&nbsp;one<br /><br />LDRB&nbsp;&nbsp;r1,&nbsp;[r0,&nbsp;#0]<br /><br />&nbsp;<br /><br />;&nbsp;short&nbsp;two<br /><br />LDRB&nbsp;&nbsp;r2,&nbsp;[r0,&nbsp;#1]<br /><br />LDRSB&nbsp;r12,&nbsp;[r0,&nbsp;#2]<br /><br />ORR&nbsp;&nbsp;&nbsp;r2,&nbsp;r12,&nbsp;r2,&nbsp;LSL&nbsp;#8<br /><br />&nbsp;<br /><br />;&nbsp;char&nbsp;three<br /><br />LDRB&nbsp;&nbsp;r3,&nbsp;[r0,&nbsp;#3]<br /><br />&nbsp;<br /><br />;&nbsp;int&nbsp;four<br /><br />ADD&nbsp;&nbsp;&nbsp;r0,&nbsp;r0,&nbsp;#4<br /><br />BL&nbsp;&nbsp;&nbsp;&nbsp;__aeabi_uread4<br />&nbsp;;&nbsp;r0&nbsp;包含了结构体c的首地址。<br /><br />&nbsp;<br /><br />;&nbsp;char&nbsp;one<br /><br />LDRB&nbsp;&nbsp;r1,&nbsp;[r0,&nbsp;#0]<br /><br />&nbsp;<br /><br />;&nbsp;short&nbsp;two<br /><br />LDRB&nbsp;&nbsp;r2,&nbsp;[r0,&nbsp;#1]<br /><br />LDRSB&nbsp;r12,&nbsp;[r0,&nbsp;#2]<br /><br />ORR&nbsp;&nbsp;&nbsp;r2,&nbsp;r12,&nbsp;r2,&nbsp;LSL&nbsp;#8<br /><br />&nbsp;<br /><br />;&nbsp;char&nbsp;three<br /><br />LDRB&nbsp;&nbsp;r3,&nbsp;[r0,&nbsp;#3]<br /><br />&nbsp;<br /><br />;&nbsp;int&nbsp;four<br /><br />LDR&nbsp;&nbsp;&nbsp;r12,&nbsp;[r0,&nbsp;#4]<br />&nbsp;<br /><br />&nbsp;<br /><br />显然以压缩方式存储结构体节省了空间但浪费了时间。以非压缩方工存储结构体加快了速度但浪费了空间。<br /><br />知道了结构体以压缩和非压缩方式存储的特点以及如何使用关键字__packed后。笔者给出在实际工作中遇到的必须使用压缩方式存储的一个例子。<br /><br />大家知道FAT文件系统的DBR&nbsp;区大小刚好为一个扇区(512字节)。DBR&nbsp;区有一系列关于系统的数据。在处理时需要将其定义为一个结构体。程序中对这个结构体进行初始化时,需要将整个扇区的内容拷贝给这个结构体。因此这个结构体的大小正好为512字节。当然这是在压缩存储的情况下。试想如果以非压缩方式存储,结果将混乱不堪。在这种情况下必须加上关建字__packed。<br /><br />&nbsp;<br /><br />该结构体定义如下:<br /><br />typedef&nbsp;__packed&nbsp;struct<br /><br />{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BS_jmpBoot[3];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:0.典型的如:0xEB,0x3E,0x90。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BS_OEMName[8];&nbsp;&nbsp;&nbsp;//ofs:3.典型的如:“MSWIN4.1”。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_BytesPerSec;&nbsp;&nbsp;&nbsp;//ofs:11.每扇区字节数。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_SecPerClus;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:13.每簇扇区数。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_RsvdSecCnt;&nbsp;&nbsp;&nbsp;//ofs:14.保留扇区数,从DBR&nbsp;到FAT&nbsp;的扇区数。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_NumFATs;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:16.FAT&nbsp;的个数。通常为2个。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_RootEntCnt;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:17.根目录项数。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_TotSec16;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:19.分区总扇区数(&lt32M&nbsp;时用)。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_Media;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:21.分区介质标识,SD卡一般用0xF8。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_FATSz16;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:22.每个FAT&nbsp;占的扇区数。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_SecPerTrk;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:24.每道扇区数。对于SD卡无意义。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_NumHeads;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:26.磁头数。对于SD卡无意义。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_HiddSec;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:28.隐藏扇区数,从MBR&nbsp;到DBR&nbsp;的扇区数。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BPB_TotSec32;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:32.分区总扇区数(&gt=32M&nbsp;时用)。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BS_DrvNum;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:36.软盘使用0x00,硬盘使用0x80。SD卡无意义。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BS_Reservedl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:37.保留。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BS_BootSig;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:38.扩展引导标记:0x29。通常对于SD卡无意义。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BS_VolID;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:39.盘序列号。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BS_VolLab[11];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//ofs:43.如“Msdos&nbsp;”。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BS_FilSysType[8];&nbsp;&nbsp;&nbsp;&nbsp;//ofs:54.“FAT16&nbsp;”。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExecutableCode[448];&nbsp;&nbsp;//ofs:62.引导代码。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;u8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ExecutableMarker[2];&nbsp;&nbsp;//ofs:510.结束标识:0xAA55。<br /><br />}&nbsp;FAT_BPB;
malvar 发表于 2008-4-3 16:02 | 显示全部楼层

re

分析得很透彻!顶一下!
lfjwfm 发表于 2008-4-5 18:05 | 显示全部楼层

顶顶

学习学习。好文
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

3

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部