關於edian大小端模式

 關於edian大小端模式

一、引子
  在各種計算機體系結構中,對於字節、字等的存儲機制有所不同,因而引發了
計算機通信領域中一個很重要的問題,即通信雙方交流的信息單元(比特、字節、
字、雙字等等)應該以什麼樣的順序進行傳送。如果不達成一致的規則,通信雙方
將無法進行正確的編/譯碼從而導致通信失敗。目前在各種體系的計算機中通常採
用的字節存儲機制主要有兩種:
big-edian和little-endian。本文簡要描述這兩種存儲機制的來歷、特點和區別。
  
  爲了敘述方便,下面先對本文中將要用到的兩個術語做簡單的定義。
  1、MSB
  MSB是Most Significant Bit/Byte的首字母縮寫,通常譯爲最重要的位或者最
重要的字節。它通常用來表明在一個bit序列(如一個byte是8個bit組成的一個序
列)或者一個byte序列(如word是兩個byte組成的一個序列)中對整個序列取值影
響最大的那個bit/byte。
  2、LSB
  LSB是Least Significant Bit/Byte的首字母縮寫,通常譯爲最不重要的位或
者最不重要的字節。它通常用來表明在一個bit序列(如一個byte是8個bit組成的
一個序列)或者一個byte序列(如word是兩個byte組成的一個序列)中對整個序
列取值影響最小的那個bit/byte。


二、endian的由來
  1、Definition
  endian: The ordering of bytes in a multi-byte number.
定義:在計算機系統體系結構中用來描述在多字節數中各個字節的存儲順序。


  2、Etymology
  The term comes from Swift's "Gulliver's Travels" via the famous paper
"On Holy Wars and a Plea for Peace" by Danny Cohen, USC/ISI IEN 137,
1980-04-01.
  The Lilliputians, being very small, had correspondingly small political
problems. The Big-Endian and Little-Endian parties debated over whether
soft-boiled eggs should be opened at the big end or the little end.[From:
Free On-Line Dictionary Of Computing or Jargon File]
  詞源:據Jargon File記載,endian這個詞來源於Jonathan
Swift在1726年寫的諷刺小說 "Gulliver's Travels"(《格利佛遊記》)。該小說
在描述Gulliver暢遊小人國時碰到了如下的一個場景。在小人國裏的小人因爲非常
小(身高6英寸)所以總是碰到一些意想不到的問題。有一次因爲對水煮蛋該從大的
一端(Big-End)剝開還是小的一端(Little-End)剝開的爭論而引發了一場戰爭,
並形成了兩支截然對立的隊伍:支持從Big-End剝開的人Swift就稱作Big-Endians
而支持從Little-End剝開的人就稱作Little-Endians……(後綴ian表明的就是支持
某種觀點的人:-)。Endian這個詞由此而來。
  
  1980年,Danny Cohen在其著名的論文"On Holy Wars and a Plea for Peace"
中爲了平息一場關於在消息中字節該以什麼樣的順序進行傳送的爭論而引用了該詞。
該文中,Cohen非常形象貼切地把支持從一個消息序列的MSB開始傳送的那夥人叫做
Big-Endians,支持從LSB開始傳送的相對應地叫做Little-Endians。此後Endian這
個詞便隨着這篇論文而被廣爲採用。


三、各種endian
  1、big-endian
  A computer architecture in which, within a given multi-byte numeric
representation, the most significant byte has the lowest address (the
word is stored "big-end-first").  
Most processors, including the IBM 370 family, the PDP-10, the
Motorola microprocessor families, and most of the various RISC designs
current in mid-1993, are big-endian. [From: Free On-Line Dictionary Of
Computing or Jargon File]
  big-endian:計算機體系結構中一種描述多字節存儲順序的術語,在這種機制
中最重要字節(MSB)存放在最低端的地址上。採用這種機制的處理器有IBM3700系
列、PDP-10、Mortolora微處理器系列和絕大多數的RISC處理器。



+----------+
| 0x34 |<-- 0x00000021
+----------+
| 0x12 |<-- 0x00000020
+----------+
圖1:雙字節數0x1234以big-endian的方式存在起始地址0x00000020中


  在Big-Endian中,對於bit序列中的序號編排方式如下(以雙字節數0x8B8A爲
例):
bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+----------------------------------------+
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+----------------------------------------+
^ 0x8B 0x8A ^
MSB LSB
圖2:Big-Endian的bit序列編碼方式


  注1:通常在TCP/IP協議棧所說的網絡序(Network Order)就是遵循Big-Endian
規則。在TCP/IP網絡通信中,通信雙方把消息按照如圖2的方式進行編碼,然後按
從MSB(Bit0)到LSB的順序在網絡上傳送。
  2、little-endian
   A computer architecture in which, within a given
16- or 32-bit word,bytes at lower addresses have lower significance (the
word is stored "little-end-first"). The PDP-11 and VAX families of
computers and Intel microprocessors and a lot of communications and
networking hardware are little-endian.
  The term is sometimes used to describe the ordering of units other
than bytes; most often, bits within a byte. [From: Free On-Line Dictionary
Of Computing or Jargon File]
  little-endian:計算機體系結構中一種描述多字節存儲順序的術語,在這種機
制中最不重要字節(LSB)存放在最低端的地址上。採用這種機制的處理器有PDP-11、
VAX、Intel系列微處理器和一些網絡通信設備。該術語除了描述多字節存儲順序外
還常常用來描述一個字節中各個比特的排放次序。


+----------+
| 0x12 |<-- 0x00000021
+----------+
| 0x34 |<-- 0x00000020
+----------+
  圖3:雙字節數0x1234以little-endian的方式存在起始地址0x00000020中


  在Little-Endian中,對於bit序列中的序號編排和Big-Endian剛好相反,其方
式如下(以雙字節數0x8B8A爲例):


bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+-----------------------------------------+
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+-----------------------------------------+
^ 0x8B 0x8A ^
MSB LSB
圖4:Little-Endian的bit序列編碼方式


  注2:通常我們說的主機序(Host Order)就是遵循Little-Endian規則。所以
當兩臺主機之間要通過TCP/IP協議進行通信的時候就需要調用相應的函數進行主機
序(Little-Endian)和網絡序(Big-Endian)的轉換。
注3:正因爲這兩種機制對於同一bit序列的序號編排方式恰恰相反,所以《現
代英漢詞典》中對MSB的翻譯爲“最高有效位”欠妥,故本文定義爲“最重要的bit
/byte”。


  3、middle-endian:
   Neither big-endian nor little-endian. Used of
perverse byte orders such as 3-4-1-2 or 2-1-4-3, occasionally found in
the packed decimal formats of some minicomputer manufacturers.[From:
Free On-Line Dictionary Of Computing or Jargon File]
  middle-endian:除了big-endian和little-endian之外的多字節存儲順序就是
middle-endian,比如以4個字節爲例:象以3-4-1-2或者2-1-4-3這樣的順序存儲的
就是middle-endian。這種存儲順序偶爾會在一些小型機體系中的十進制數的壓縮格
式中出現。
四、收尾
  要詳細解釋這兩種編碼順序已經超出本文所涉及的內容,如果你有興趣的話可
以參考上面提及的Danny Cohen的論文("On Holy Wars and a Plea for Peace"),
該論文詳細的描述了這兩種編碼順序的歷史、所基於的數學理論和各自擁護者爭論
的焦點等知識,絕對可以大飽你打破沙鍋問到底的內心需要。


什麼是字節序?
   字節序,顧名思義字節的順序,再多說兩句就是大於一個字節類型的數據在內存中的存放順序(一個字節的數據當然就無需談順序的問題了)。其實大部分人在實際 的開發中都很少會直接和字節序打交道。唯有在跨平臺以及網絡程序中字節序纔是一個應該被考慮的問題。在所有的介紹字節序的文章中都會提到字節序分爲兩 類:Big-Endian和Little-Endian。引用標準的Big-Endian和Little-Endian的定義如下:
a) Little-Endian就是低位字節排放在內存的低地址端,高位字節排放在內存的高地址端。
b) Big-Endian就是高位字節排放在內存的低地址端,低位字節排放在內存的高地址端。
c) 網絡字節序:TCP/IP各層協議將字節序定義爲Big-Endian,因此TCP/IP協議中使用的字節序通常稱之爲網絡字節序。
PS:有些文章中稱低位字節爲最低有效位,高位字節爲最高有效位。
Big endian means that the most significant byte of any multibyte data field is stored at the lowest memory address, which is also the address of the larger field.
Little endian means that the least significant byte of any multibyte data field is stored at the lowest memory address, which is also the address of the larger field.

   什麼是高/低地址端 什麼是高/低字節
   首先我們要知道我們C程序映像中內存的空間佈局情況:在《C專家編程》中或者《Unix環境高級編程》中有關於內存空間佈局情況的說明,大致如下圖:
----------------------- 最高內存地址 0xffffffff
| 棧底
.
. 棧
.
棧頂
-----------------------
|
|
/|/

NULL (空洞)

/|/
|
|
-----------------------

-----------------------
未初始化的數據
----------------(統稱數據段)
初始化的數據
-----------------------
正文段(代碼段)
----------------------- 最低內存地址 0x00000000

以上圖爲例如果我們在棧上分配一個unsigned char buf[4],那麼這個數組變量在棧上是如何佈局的呢?看下圖:
棧底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂 (低地址)
現 在我們弄清了高/低地址,接着考慮高/低字節。如果我們有一個32位無符號整型0x12345678,那麼高位是什麼,低位又是什麼呢?其實很簡單。在十 進制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進制也是如此。就拿 0x12345678來說,從高位到低位的字節依次是0x12、0x34、0x56和0x78。
高/低地址端和高/低字節都弄清了。我們再來回顧一下Big-Endian和Little-Endian的定義,並用圖示說明兩種字節序:
以unsigned int value = 0x12345678爲例,分別看看在兩種字節序下其存儲情況,我們可以用unsigned char buf[4]來表示value:


Big-Endian: 低地址存放高位,如下圖:
棧底 (高地址)
---------------
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
---------------
棧頂 (低地址)

Little-Endian: 低地址存放低位,如下圖:
棧底 (高地址)
---------------
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位
--------------
棧頂 (低地址)

   現有的平臺上Intel的X86採用的是Little-Endian,而像Sun的SPARC採用的就是Big-Endian。那麼在跨平臺或網絡程序中如何實現字節序的轉換呢?這個通過C語言的移位操作很容易實現,例如下面的宏:

#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)

#define htons(A)   (A)
#define htonl(A)     (A)
#define ntohs(A)   (A)
#define ntohl(A)    (A)

#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)

#define htons(A)     ((((uint16)(A) & 0xff00) >> 8) | /
                               (((uint16)(A) & 0x00ff) << 8))
#define htonl(A)     ((((uint32)(A) & 0xff000000) >> 24) | /
                              (((uint32)(A) & 0x00ff0000) >> 8) | /
                              (((uint32)(A) & 0x0000ff00) << 8) | /
                              (((uint32)(A) & 0x000000ff) << 24))
#define ntohs htons
#define ntohl htohl

#else

#error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."

#endif

   如何檢查處理器是big-endian還是little-endian?
   由於聯合體union的存放順序是所有成員都從低地址開始存放,利用該特性就可以輕鬆地獲得了CPU對內存採用Little-endian還是Big-endian模式讀寫。例如:
   int checkCPUendian(){
        union {
             unsigned int a;
             unsigned char b;            
        }c;
        c.a = 1;
        return (c.b == 1);       
   }   /*return 1 : little-endian, return 0:big-endian*/

 原文地址 http://hi.baidu.com/%C8%FD%C9%EE/blog/item/6abb3d7779c0961db151b96b.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章