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

7

6

5

4

3

2

1

0

0

Operation Code (28h)

1

Reserved

( 0 0 0 )b

DPO

FUA

( 0 )b

Reserved

( 0 0 0 )b

RelAdr ( 0 )b

2

(MSB)

LBA

 

(LSB)

3

4

5

6

Reserved  ( 00 h)

7

(MSB)                                                         

 Transfer Length                        (LSB)

8

9

Controller

 

 

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

typedef struct cdb1tag

{

              uchar_t         opcode;

              uchar_t         lun;

              uint_t           lba;

              uchar_t         rsv1;

              ushort_t     block;

              uchar_t         cntl;

} CDB1;

 

假设要发行一个Read操作, LBA是0x01020304. Transfer Length是255(0x00ff).

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

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

 

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

 

Byte

(BIG_ENDIAN)

0

 

1

 

2

(MSB)    01

3

02

4

03

5

04    (LSB)

6

 

7

(MSB)    00            

8

          ff    (LSB)

9

 

Byte

(LITTLE_ENDIAN)

0

 

1

 

2

(LSB)    04

3

03

4

02

5

01    (MSB)

6

 

7

(LSB)     ff

8

          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 阅读(726) 评论(0)  编辑  收藏 所属分类: cpp 、ZZ