一、字節(jié)序定義
字節(jié)序,顧名思義字節(jié)的順序,再多說兩句就是大于一個字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序(一個字節(jié)的數(shù)據(jù)當(dāng)然就無需談順序的問題了)。
其實(shí)大部分人在實(shí)際的開發(fā)中都很少會直接和字節(jié)序打交道。唯有在跨平臺以及網(wǎng)絡(luò)程序中字節(jié)序才是一個應(yīng)該被考慮的問題。
在所有的介紹字節(jié)序的文章中都會提到字節(jié)序分為兩類:Big-Endian和Little-Endian。引用標(biāo)準(zhǔn)的Big-Endian和Little-Endian的定義如下:
a) Little-Endian就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端。
b) Big-Endian就是高位字節(jié)排放在內(nèi)存的低地址端,低位字節(jié)排放在內(nèi)存的高地址端。
c) 網(wǎng)絡(luò)字節(jié)序:4個字節(jié)的32 bit值以下面的次序傳輸:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。這種傳輸次序稱作大端字節(jié)序。由于 TCP/IP首部中所有的二進(jìn)制整數(shù)在網(wǎng)絡(luò)中傳輸時都要求以這種次序,因此它又稱作網(wǎng)絡(luò)字節(jié)序。比如,以太網(wǎng)頭部中2字節(jié)的“ 以太網(wǎng)幀類型”,表示后面數(shù)據(jù)的類型。對于ARP請求或應(yīng)答的以太網(wǎng)幀類型 來說,在網(wǎng)絡(luò)傳輸時,發(fā)送的順序是0x08,0x06。在內(nèi)存中的映象如下圖所示:
棧底 (高地址)
---------------
0x06 -- 低位
0x08 -- 高位
---------------
棧頂 (低地址)
該字段的值為0x0806。按照大端方式存放在內(nèi)存中。
二、高/低地址與高低字節(jié)
首先我們要知道我們C程序映像中內(nèi)存的空間布局情況:在《C專家編程》中或者《Unix環(huán)境高級編程》中有關(guān)于內(nèi)存空間布局情況的說明,大致如下圖:
----------------------- 最高內(nèi)存地址 0xffffffff
| 棧底
.
. 棧
.
棧頂
-----------------------
|
|
/|/
NULL (空洞)
/|/
|
|
-----------------------
堆
-----------------------
未初始化的數(shù)據(jù)
----------------(統(tǒng)稱數(shù)據(jù)段)
初始化的數(shù)據(jù)
-----------------------
正文段(代碼段)
----------------------- 最低內(nèi)存地址 0x00000000
以上圖為例如果我們在棧上分配一個unsigned char buf[4],那么這個數(shù)組變量在棧上是如何布局的呢[注1]?看下圖:
棧底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂 (低地址)
現(xiàn) 在我們弄清了高低地址,接著來弄清高/低字節(jié),如果我們有一個32位無符號整型0x12345678(呵呵,恰好是把上面的那4個字節(jié)buf看成一個整 型),那么高位是什么,低位又是什么呢?其實(shí)很簡單。在十進(jìn)制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進(jìn)制也是如此。就拿 0x12345678來說,從高位到低位的字節(jié)依次是0x12、0x34、0x56和0x78。
高低地址和高低字節(jié)都弄清了。我們再來回顧一下Big-Endian和Little-Endian的定義,并用圖示說明兩種字節(jié)序:
以unsigned int value = 0x12345678為例,分別看看在兩種字節(jié)序下其存儲情況,我們可以用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) -- 低位
---------------
棧頂 (低地址)
在現(xiàn)有的平臺上Intel的X86采用的是Little-Endian,而像Sun的SPARC采用的就是Big-Endian。
三、例子
嵌入式系統(tǒng)開發(fā)者應(yīng)該對Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU對操作數(shù)的存放方式是從低字節(jié)到高字節(jié),而Big-endian模式對操作數(shù)的存放方式是從高字節(jié)到低字節(jié)。
例如,16bit寬的數(shù)0x1234在Little-endian模式CPU內(nèi)存中的存放方式(假設(shè)從地址0x4000開始存放)為:
內(nèi)存地址 存放內(nèi)容
0x4001 0x12
0x4000 0x34
而在Big-endian模式CPU內(nèi)存中的存放方式則為:
內(nèi)存地址 存放內(nèi)容
0x4001 0x34
0x4000 0x12
32bit寬的數(shù)0x12345678在Little-endian模式CPU內(nèi)存中的存放方式(假設(shè)從地址0x4000開始存放)為:
內(nèi)存地址 存放內(nèi)容
0x4003 0x12
0x4002 0x34
0x4001 0x56
0x4000 0x78
而在Big-endian模式CPU內(nèi)存中的存放方式則為:
內(nèi)存地址 存放內(nèi)容
0x4003 0x78
0x4002 0x56
0x4001 0x34
0x4000 0x12