发 帖  
原厂入驻New

RealView MDK中结构体存储方式

2008-8-2 10:17:37  3340
分享

对于RISC机器来说,对齐访问可以提高效率。ARMRISC机器,因此在多数情况下它以对齐方式访问,即访问的地址一般是42的倍数。但在某些特殊应用上,对齐访问可能会带来麻烦。下面笔者以自身经历来说明有些情况是不允许对齐访问的,好在强大的MDK早就意料到这些特殊应用,并有相应的对策。microsoft-com:office:office" />

times New="New" Roman'; mso-hansi-font-family: 'Times New="New" Roman'">下面举例说明结构以对齐方式和非对齐方式存储的差别。

下面以三种不同的方式定义了结构体foo,见表一。其中第一种是常用的(默认情况)定义方式。第二种和第三种方式均以压缩方式存储,以非对齐方式访问。其中第二种方式关键字__packed修饰整个结构体,表明整个结构体以压缩方式存储;第三种方式关键字__packed修饰结构体中的某个域,被修饰的域以压缩的方式存储。而其它部分则采用非压缩方式。当然在示例结构体foo中,后两种定义方法达到的效果一样。

在第一种方式中,结构体成员one占用两个字节;成员two占用两个字节;成员three占用4个字节;成员four占用4个字节。 而在第二种和第三种方式中它们分别占用1个字节、两个字节、一个字节、4个字节。如果读者看到这还不是很清楚的话,那么请看其对应的汇编代码,见表二。

表一 三种定义结构体方式对比

非压缩方式存储(对齐访问)

将整个结构体以压缩方式存储

将结构体中的部分成员压缩方式存储

Struct foo

{

    char one;

    short two;

    char three;

    int four;

} c;

__packed struct foo

{

    char one;

    short two;

    char three;

    int four;

} c;

struct foo

{

    char one;

    __packed short two;

    char three;

    int four;

} c;

 

表二 三种定义结构体方式对应用汇编代码

非压缩方式存储(对齐方式)

将整个结构体以压缩方式存储

将结构体中的部分成员压缩方式存储

; r0 包含了结构体c的首地址。

 

LDRB    r1, [r0, #0]

LDRSH   r2, [r0, #2]

LDRB    r3, [r0, #4]

LDR     r12, [r0, #8]

; r0 包含了结构体c的首地址。

 

; char one

LDRB  r1, [r0, #0]

 

; short two

LDRB  r2, [r0, #1]

LDRSB r12, [r0, #2]

ORR   r2, r12, r2, LSL #8

 

; char three

LDRB  r3, [r0, #3]

 

; int four

ADD   r0, r0, #4

BL    __aeabi_uread4

; r0 包含了结构体c的首地址。

 

; char one

LDRB  r1, [r0, #0]

 

; short two

LDRB  r2, [r0, #1]

LDRSB r12, [r0, #2]

ORR   r2, r12, r2, LSL #8

 

; char three

LDRB  r3, [r0, #3]

 

; int four

LDR   r12, [r0, #4]

 

显然以压缩方式存储结构体节省了空间但浪费了时间。以非压缩方工存储结构体加快了速度但浪费了空间。

知道了结构体以压缩和非压缩方式存储的特点以及如何使用关键字__packed后。笔者给出在实际工作中遇到的必须使用压缩方式存储的一个例子。

大家知道FAT文件系统的DBR 区大小刚好为一个扇区(512字节)。DBR 区有一系列关于系统的数据。在处理时需要将其定义为一个结构体。程序中对这个结构体进行初始化时,需要将整个扇区的内容拷贝给这个结构体。因此这个结构体的大小正好为512字节。当然这是在压缩存储的情况下。试想如果以非压缩方式存储,结果将混乱不堪。在这种情况下必须加上关建字__packed

 

该结构体定义如下:

typedef __packed struct

{

       u8         BS_jmpBoot[3];     //ofs:0.典型的如:0xEB,0x3E,0x90

       u8         BS_OEMName[8];   //ofs:3.典型的如:“MSWINasspace="False" sourcevalue="4.1" unitname="”" w:st="on">4.1

       u16        BPB_BytesPerSec;   //ofs:11.每扇区字节数。

       u8         BPB_SecPerClus;    //ofs:13.每簇扇区数。

       u16        BPB_RsvdSecCnt;   //ofs:14.保留扇区数,从DBR FAT 的扇区数。

       u8         BPB_NumFATs;     //ofs:16.FAT 的个数。通常为2个。

       u16        BPB_RootEntCnt;    //ofs:17.根目录项数。

       u16        BPB_TotSec16;      //ofs:19.分区总扇区数(<32M 时用)

       u8         BPB_Media;        //ofs:21.分区介质标识,SD卡一般用0xF8

       u16        BPB_FATSz16;      //ofs:22.每个FAT 占的扇区数。

       u16        BPB_SecPerTrk;     //ofs:24.每道扇区数。对于SD卡无意义。

       u16        BPB_NumHeads;     //ofs:26.磁头数。对于SD卡无意义。

       u32        BPB_HiddSec;       //ofs:28.隐藏扇区数MBR DBR 的扇区数。

       u32        BPB_TotSec32;      //ofs:32.分区总扇区数(>=32M 时用)

       u8         BS_DrvNum;        //ofs:36.软盘使用0x00,硬盘使用0x80SD卡无意义。

       u8         BS_Reservedl;       //ofs:37.保留。

       u8         BS_BootSig;        //ofs:38.扩展引导标记:0x29。通常对于SD卡无意义。

       u32        BS_VolID;          //ofs:39.盘序列号。

       u8         BS_VolLab[11];      //ofs:43.如“Msdos ”。

       u8         BS_FilSysType[8];    //ofs:54.FAT16

       u8         ExecutableCode[448];  //ofs:62.引导代码。

       u8         ExecutableMarker[2];  //ofs:510.结束标识:0xAA55

} FAT_BPB;
0
2008-8-2 10:17:37   评论 分享淘帖
2 个讨论

拜读

2009-7-8 18:50:04 评论

举报

拜读

拜读

2009-7-8 18:50:20 评论

举报

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发表新帖
关闭

站长推荐 上一条 /7 下一条

快速回复 返回顶部 返回列表