天天看點

小端位元組序與大端位元組序

在各種計算機體系結構中,對于位元組、字等的存儲機制有所不同,因而引發了計算機通信領域中一個很重要的問題,即通信雙方交流的資訊單元(比特、位元組、字、雙字等等)應該以什麼樣的順序進行傳送。如果不達成一緻的規則,通信雙方将無法進行正确的編/譯碼進而導緻通信失敗。

目前在各種體系的計算機中通常采用的位元組存儲機制主要有兩種:Big-Endian 和 Little-Endian,下面先從位元組序說起。

1、什麼是位元組序

位元組序,顧名思義位元組的順序,就是大于一個位元組類型的資料在記憶體中的存放順序(一個位元組的資料當然就無需談順序的問題了)。

位元組序分為兩類:Big-Endian 和 Little-Endian,引用标準的 Big-Endian 和 Little-Endian 的定義如下:

  • Little-Endian:就是低位位元組排放在記憶體的低位址端,高位位元組排放在記憶體的高位址端。
  • Big-Endian:就是高位位元組排放在記憶體的低位址端,低位位元組排放在記憶體的高位址端。
  • 網絡位元組序:TCP/IP各層協定将位元組序定義為 Big-Endian(這與主機序相反),是以TCP/IP協定中使用的位元組序通常稱之為網絡位元組序。

1.1 什麼是高/低位址端

首先我們要知道我們 C 程式映像中記憶體的空間布局情況:在《C專家程式設計》中或者《Unix環境進階程式設計》中有關于記憶體空間布局情況的說明,大緻如下圖:

----------------------- 最高記憶體位址 0xffffffff

棧底

棧頂

-----------------------

NULL (空洞) 

未初始化的資料

----------------------- 統稱資料段

初始化的資料

正文段(代碼段)

----------------------- 最低記憶體位址 0x00000000

以上圖為例如果我們在棧上配置設定一個unsigned char buf[4],那麼這個數組變量在棧上是如何布局的呢?看下圖:

棧底 (高位址)

----------

buf[3] 

buf[2]

buf[1]

buf[0]

棧頂(低位址)

1.2 什麼是高/低位元組

現在我們弄清了高/低位址,接着考慮高/低位元組。有些文章中稱低位位元組為最低有效位,高位位元組為最高有效位。如果我們有一個32位無符号整型 0x12345678,那麼高位是什麼,低位又是什麼呢?其實很簡單。在十進制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進制也是如此。就拿 0x12345678 來說,從高位到低位的位元組依次是 0x12、0x34、0x56 和 0x78。

高/低位址端和高/低位元組都弄清了。我們再來回顧一下 Big-Endian 和 Little-Endian 的定義,并用圖示說明兩種位元組序:

以unsigned int value = 0x12345678 為例,分别看看在兩種位元組序下其存儲情況,我們可以用 unsignedchar 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) -- 低位

--------------

棧 頂 (低位址)

2、各種 Endian

2.1 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 |

+----------------------------------------+

圖 2:Big-Endian的bit序列編碼方式

2.2 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 65 4 3 2 1 0

圖 4:Little-Endian的bit序列編碼方式

注2:通常我們說的主機序(Host Order)就是遵循 Little-Endian 規則。是以當兩台主機之間要通過TCP/IP協定進行通信的時候就需要調用相應的函數進行主機序(Little-Endian)和網絡序(Big-Endian)的轉換。

注3:正因為這兩種機制對于同一bit序列的序号編排方式恰恰相反,是以《現代英漢詞典》中對MSB的翻譯為“最高有效位”欠妥,故本文定義為“最重要的bit/byte”。

2.3 Middle-Endian

除了Big-Endian和Little-Endian之外的多位元組存儲順序就是Middle- Endian,比如以4個位元組為例:象以3-4-1-2或者2-1-4-3這樣的順序存儲的就是Middle-Endian。這種存儲順序偶爾會在一些小型機體系中的十進制數的壓縮格式中出現。

嵌入式系統開發者應該對Little-endian和Big-endian模式非常了解。采用 Little-endian模式的CPU對操作數的存放方式是從低位元組到高位元組,而Big-endian模式對操作數的存放方式是從高位元組到低位元組。 32bit寬的數0x12345678在Little-endian模式CPU記憶體中的存放方式(假設從位址0x4000開始存放)為: 

小端位元組序與大端位元組序

3、優缺點

Big-Endian 優點:靠首先提取高位位元組,你總是可以由看看在偏移位置為0的位元組來确定這個數字是正數還是負數。你不必知道這個數值有多長,或者你也不必過一些位元組來看這個數值是否含有符号位。這個數值是以它們被列印出來的順序存放的,是以從二進制到十進制的函數特别有效。因而,對于不同要求的機器,在設計存取方式時就會不同。

Little-Endian 優點:提取一個,兩個,四個或者更長位元組資料的彙編指令以與其他所有格式相同的方式進行:首先在偏移位址為0的地方提取最低位的位元組,因為位址偏移和位元組數是一對一的關系,多重精度的數學函數就相對地容易寫了。

如果你增加數字的值,你可能在左邊增加數字(高位非指數函數需要更多的數字)。是以,經常需要增加兩位數字并移動存儲器裡所有Big-endian順序的數字,把所有數向右移,這會增加計算機的工作量。不過,使用Little- Endian的存儲器中不重要的位元組可以存在它原來的位置,新的數可以存在它的右邊的高位位址裡。這就意味着計算機中的某些計算可以變得更加簡單和快速。

4、網絡位元組順序

1、位元組内的比特位不受這種順序的影響

比如一個位元組 1000 0000 (或表示為十六進制 80H)不管是什麼順序其記憶體中的表示法都是這樣。

2、大于1個位元組的資料類型才有位元組順序問題

比如 Byte A,這個變量隻有一個位元組的長度,是以根據上一條沒有位元組順序問題。是以位元組順序是“位元組之間的相對順序”的意思。

3、大于1個位元組的資料類型的位元組順序有兩種

比如 short B,這是一個兩位元組的資料類型,這時就有位元組之間的相對順序問題了。

網絡位元組順序是“所見即所得”的順序。而Intel類型的CPU的位元組順序與此相反。

比如上面的 short B=0102H(十六進制,每兩位表示一個位元組的寬度)。所見到的是“0102”,按一般數學常識,數軸從左到右的方向增加,即記憶體位址從左到右增加的話,在記憶體中這個 short B的位元組順序是:

01 02

這就是網絡位元組順序。所見到的順序和在記憶體中的順序是一緻的!

假設通過抓包得到網絡資料的兩個位元組流為:01 02

而相反的位元組順序就不同了,其在記憶體中的順序為:02 01

如果這表示兩個 Byte類型的變量,那麼自然不需要考慮位元組順序的問題。如果這表示一個 short 變量,那麼就需要考慮位元組順序問題。根據網絡位元組順序“所見即所得”的規則,這個變量的值就是:0102

假設本地主機是Intel類型的,那麼要表示這個變量,有點麻煩:

定義變量 short X,位元組流位址為:pt,按順序讀取記憶體是為x=*((short*)pt);

那麼X的記憶體順序當然是 01 02按非 “所見即所得” 的規則,這個記憶體順序和看到的一樣顯然是不對的,是以要把這兩個位元組的位置調換。調換的方法可以自己定義,但用已經有的API還是更為友善。

5、網絡位元組順序與主機位元組順序

  • 網絡位元組順序NBO(Network Byte Order):按從高到低的順序存儲,在網絡上使用統一的網絡位元組順序,可以避免相容性問題。
  • 主機位元組順序(HBO,Host Byte Order):不同的機器HBO不相同,與CPU設計有關計算機資料存儲有兩種位元組優先順序:高位位元組優先和低位位元組優先。Internet上資料以高位位元組優先順序在網絡上傳輸,是以對于在内部是以低位位元組優先方式存儲資料的機器,在Internet上傳輸資料時就需要進行轉換。