jinfeng_wang

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

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
          http://www.aygfsteel.com/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 閱讀(685) 評論(0)  編輯  收藏 所屬分類: cpp 、ZZ
          主站蜘蛛池模板: 富锦市| 宜黄县| 清新县| 阳信县| 建湖县| 驻马店市| 定结县| 潜山县| 凭祥市| 广元市| 定日县| 驻马店市| 溧水县| 剑阁县| 惠来县| 磐安县| 白山市| 正镶白旗| 太仆寺旗| 双柏县| 山东省| 广西| 余姚市| 同仁县| 黄山市| 安龙县| 唐海县| 景德镇市| 阿克陶县| 望奎县| 普兰店市| 高青县| 南乐县| 台江县| 日喀则市| 本溪| 印江| 荣昌县| 灵台县| 会理县| 浠水县|