端模式(Endian)的這個詞出自Jonathan Swift書寫的《格列佛遊記》。
這本書根據将雞蛋敲開的方法不同将所有的人分為兩類,從圓頭開始将雞蛋敲開的人被歸為Big Endian,從尖頭開始将雞蛋敲開的人被歸為Littile Endian。
小人國的内戰就源于吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開。
在計算機業Big Endian和Little Endian也幾乎引起一場戰争。在計算機業界,Endian表示資料在存儲器中的存放順序。
Little endian 和Big endian 是CPU 存放資料的兩種不同順序。
對于整型、長整型等資料類型,Big endian 認為第一個位元組是最高位位元組(按照從低位址到高位址的順序存放資料的高位位元組到低位位元組);
而Little endian 則相反,它認為第一個位元組是最低位位元組(按照從低位址到高位址的順序存放資料的低位位元組到高位位元組)。
例如,假設從記憶體位址0x0000 開始有以下資料:
0x12 0x34 0xab 0xcd
如 果我們去讀取一個位址為0x0000 的四個位元組變量,若位元組序為big-endian,則讀出結果為0x1234abcd;若位元組序位little-endian,則讀出結果為 0xcdab3412。如果我們将0x1234abcd 寫入到以0x0000 開始的記憶體中,則Little endian 和Big endian 模式的存放結果如下:
位址 0x0000 0x0001 0x0002 0x0003
big-endian 0x12 0x34 0xab 0xcd
little-endian 0xcd 0xab 0x34 0x12
一般來說,x86 系列CPU 都是little-endian 的位元組序,PowerPC 通常是Big endian,還有的CPU 能通過跳線來設定CPU 工作于Little endian 還是Big endian 模式。
測試大小端一般使用union的特性。union是一個聯合體,所有變量公用一塊記憶體,隻是在不同的時候解釋不同。其在記憶體中存儲是按最長的那個變量所需要的位數來開辟記憶體的。
#include <stdio.h>
typedef union{
unsigned short int value;
unsigned char byte[2];
}to;
int main(int argc, char *argv)
{
to typeorder ;
typeorder.value = 0xabcd;
if(typeorder.byte[0] == 0xcd && typeorder.byte[1]==0xab){
printf("Low endian byte order"
"byte[0]:0x%x,byte[1]:0x%x\n",
typeorder.byte[0],
typeorder.byte[1]);
}
if(typeorder.byte[0] == 0xab && typeorder.byte[1]==0xcd){
printf("High endian byte order"
"byte[0]:0x%x,byte[1]:0x%x\n",
typeorder.byte[0],
typeorder.byte[1]);
}
return 0;
}
======================================================
實作同樣的功能,我們來看看Linux 作業系統中相關的源代碼是怎麼做的:
static union { char c[4]; unsigned long mylong; } endian_test = {{ 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.mylong)
Linux 的核心作者們僅僅用一個union 變量和一個簡單的宏定義就實作了一大段代碼同樣的功能!
由以上一段代碼我們可以深刻領會到Linux 源代碼的精妙之處!
(如果ENDIANNESS=’l’表示系統為little endian,為’b’表示big endian )