jinfeng_wang

G-G-S,D-D-U!

BlogJava 首页 新随笔 联系 聚合 管理
  400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
http://www.blogjava.net/Files/jinfeng_wang/Endian.rar


Endian 
介绍

1.       Endian简介

Endian可以看作是系统的一种属性, 它指示多字节整数是从左向右放, 还是从右向左放. 它有两种形式:

Ÿ           Big Endian

Ÿ           Little Endian

 

BE把多字节整数的MSB(Most Significant Byte)存储在最低的地址上, LSB(Least Significant Byte)顺序存放在最高的地址上, LE正好相反.

 

4-bytes数据0x01020304以两种不同的方式存储如下:

00000001 00000010 00000011 00000100

Address

00

01

02

03

Big-Endian

00000001

00000010

00000011

00000100

Little-Endian

00000100

00000011

00000010

00000001

 

所有的处理器必须指定它用Big Endian还是Little Endian. Intel's 80x86 processor

little endian. Sun's SPARC, Motorola's 68K, PowerPC系列是big endian. 有些处理器甚至设置了一个标志位可以选择所需要的Endian.

 

2.       出现的问题

如果我们不了解Endian在数据存储上的差异, 使用的时候就有可能出现问题, 比如我们想要的是0x01020304,但是在little endian的情况下, 就有可能得到0x04030201.

如何避免错误的数据呢? 首先先看一下系统是如何存取数据的.


下面是同一组数据在两种endian下的memory dump:

char              c1 = 1;
char       c2 = 2;
short     s  = 255; // 0x00ff
long       l  = 0x11223344;

Offset    :      Memory dump
0x0000 :    
01 02 00 FF
0x0004 :     11 22 33 44

A Big-Endian memory dump

 

char              c1 = 1;
char       c2 = 2;
short     s  = 255; // 0x00ff
long       l  = 0x11223344;

Offset    :      Memory dump
0x0000 :    
01 02 FF 00
0x0004 :     44 33 22 11

A Little-Endian memory dump

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


上图表示了数据的存放方式, 虽然s, l在两种endina下的存储方式不同, 但取出s, l的时候系统还是会还原成原来的值, 数据是不会改变的. 就是说平常使用的过程中, 我们不必关心这种存取的过程.

 

那么在什么情况下会造成数值的改变呢? 我们从存数据和取数据两个方面进行说明

2.1.      存数据

有一些接口和规范规定了必须以某种Endian的格式进行通讯, 大多数都规定以Big Endian的格式. 比如SCSI command数据的传输, TCP/IP网络协议等.

      

       下面是10 字节的Read command, CDB格式如下:

Bit

Byte

Operation Code (28h)

1

Reserved

( 0 0 0 )b

DPO

FUA

( 0 )b

Reserved

( 0 0 0 )b

RelAdr ( 0 )b

(MSB)

LBA

 

(LSB)

Reserved  ( 00 h)

(MSB)                                                         

 Transfer Length                        (LSB)

Controller

 

 

我们定义如下的结构体填充.

typedef struct cdb1tag

{

              uchar_t         opcode;

              uchar_t         lun;

              uint_t           lba;

              uchar_t         rsv1;

              ushort_t     block;

              uchar_t         cntl;

} CDB1;

 

假设要发行一个Read操作, LBA0x01020304. Transfer Length255(0x00ff).

我们需要对CDB进行填充. 赋值:

lba=0x01020304;              block=0x00ff;      …(其他参数不讨论)

 

下面我们看看赋值后Big EndianLittle Endian是怎样存储这段数据的:

 

Byte

(BIG_ENDIAN)

0

 

1

 

(MSB)    01

02

03

04    (LSB)

6

 

(MSB)    00            

          ff    (LSB)

9

 

Byte

(LITTLE_ENDIAN)

0

 

1

 

(LSB)    04

03

02

01    (MSB)

6

 

(LSB)     ff

          00    (MSB)

9

 

 

 

 


2.2.      取数据

同上面讲到的, 如果规定了必须以某种Endian通讯, 则必须按照规定的顺序把数据取出来, 这种情况同存数据的例子, 只不过一个是存, 一个是取.

 

union{

char  c_num[4]; // 01 02 03 04
int i_num;

}dev;

Offset    :      Memory dump

0x0000 :     01 02 03 04

i_num=  0x04030201 (LE)  :  0x01020304 (BE)

另外, 不按照系统存储的方式取数据, 有时会发生意外. 比如说我们是以一个字节一个字节存储的数据, 却以4个字节为一组取出.

 

 

 

 

 

 

不过有的数据比较特殊, 即使颠倒字节顺序,  数值也不发生改变

例如:     0  0x1111  0x01020201

 

3.       解决方法

Ÿ           多字节数据以单字节写入/读出

IN:

(unsigned char)((lba & 0Xff000000) >> 24)  à MSB

(unsigned char)((lba & 0X00ff0000) >> 16)

(unsigned char)((lba & 0X0000ff00) >> 8)

(unsigned char) (lba & 0X000000ff)                à LSB

OUT:

endian_dump()

 

Ÿ           交换字节 byte_swap()

 

posted on 2007-05-28 15:08 jinfeng_wang 阅读(588) 评论(0)  编辑  收藏 所属分类: cppZZ

只有注册用户登录后才能发表评论。


网站导航: