簡明區分
下面以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) -- 低位
--------------
低地址
記憶體地址 | 小端模式存放內容 | 大端模式存放內容 |
0x4000 | 0x78 | 0x12 |
0x4001 | 0x56 | 0x34 |
0x4002 | 0x34 | 0x56 |
0x4003 | 0x12 | 0x78 |
名詞解析
大端模式
所謂的大端模式(Big-endian),是指數據的高位元組,保存在記憶體的低地址中,而數據的低位元組,保存在記憶體的高地址中,這樣的存儲模式有點兒類似於把數據當作字元串順序處理:地址由小向大增加,而數據從高位往低位放;
例子:
0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000
0000440: b484 6c4e 004e ed00 0000 0000 0100 0000
在大端模式下,前32位應該這樣讀: e6 84 6c 4e ( 假設int占4個位元組)
記憶方法: 地址的增長順序與值的增長順序相反
小端模式
所謂的小端模式(Little-endian),是指數據的高位元組保存在記憶體的高地址中,而數據的低位元組保存在記憶體的低地址中,這種存儲模式將地址的高低和數據位權有效地結合起來,高地址部分權值高,低地址部分權值低,和我們的邏輯方法一致。
例子:
0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000
0000440: b484 6c4e 004e ed00 0000 0000 0100 0000
在小端模式下,前32位應該這樣讀: 4e 6c 84 e6( 假設int占4個位元組)
記憶方法: 地址的增長順序與值的增長順序相同
大小端模式
為什麼會有大小端模式之分呢?這是因為在計算機系統中,我們是以位元組為單位的,每個地址單元都對應著一個位元組,一個位元組為 8bit。但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對於位數大於 8位的處理器,例如16位或者32位的處理器,由於暫存器寬度大於一個位元組,那么必然存在著一個如何將多個位元組安排的問題。因此就導致了大端存儲模式和小端存儲模式。例如一個16bit的short型x,在記憶體中的地址為0x0010,x的值為0x1122,那么0x11為高位元組,0x22為低位元組。對於 大端模式,就將0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,剛好相反。我們常用的X86結構是小端模式,而KEIL C51則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以隨時在程式中(在ARM Cortex 系列使用REV、REV16、REVSH指令 )進行大小端的切換。
圖解
對於0x11223344 儲存如下
名字由來
在喬納森·斯威夫特的著名諷刺小說《格列夫遊記》中,小人國內部分裂成Big-endian和Little-endian兩派,區別在於一派要求從雞蛋的大頭把雞蛋打破,另一派要求從雞蛋的小頭把雞蛋打破。斯威夫特藉以諷刺英國的政黨之爭,在計算機工業中指數據儲存順序的分歧。
編輯器模式
下面這段代碼可以用來測試一下你的編譯器是大端模式還是小端模式:
若x0=0x11,則是大端; 若x0=0x22,則是小端......
從上面的程式還可以看出,數據定址時,用的是低位位元組的地址。
簡單大小端轉換的宏
作業系統
(如果ENDIANNESS=’l’表示系統為little endian,為’b’表示big endian )。
判斷處理器
通過下列的程式可以確認在某個硬體平台上的某個作業系統是大端還是小端:
VB6:
在英特爾處理器,Windows10作業系統上,對話框顯示的結果是99 FB E4 15,與直接求出來的16進制值15 E4 FB 99正好相反,所以是小端的。
C++語言(VS2013下,控制台項目):
在英特爾處理器,Windows10作業系統上,控制台顯示的結果是99 FB E4 15,與直接求出來的16進制值15 E4 FB 99正好相反,所以也證明是小端的。
C語言(VC++6.0,控制台工程):
在英特爾處理器,Windows10作業系統上,結果跟上面是一樣的,輸出的16進制數是反序的,證明是小端系統。
C#(VS2013下,控制台項目):
在英特爾處理器,Windows10作業系統上,結果跟上面還還是一樣的,輸出的16進制數是反序的,證明是小端系統。
MDK(Keil5,STM32F407)C語言:
編譯連線然後下載到開發板上,然後啟動調試,通過監視視窗可以看到u的地址,然後在記憶體視窗可以看到位元組序是反序的,所以說明STM32F407是小端的。據某些資料說ARM核心是可以設定大小端的,但是STM32是外設自動進入了小端,似乎是無法調整的。
89C52(Keil5)C語言:
最後來一個大端的例子。手頭上沒有51的開發板,所以用的是軟體仿真。
注意看了,C52是8位的處理器,long才是4個位元組的,看監視視窗longbit的值就知道了(紫色框)。然後再看記憶體視窗,就會發現u的存儲是跟原始數據給的順序是一樣的,所以C51和C52是大端的!!
現階段狀況
目前Intel的80x86系列晶片是唯一還在堅持使用小端的晶片,ARM晶片默認採用小端,但可以切換為大端;而MIPS等晶片要么採用全部大端的方式儲存,要么提供選項支持大端——可以在大小端之間切換。另外,對於大小端的處理也和編譯器的實現有關,在C語言中,默認是小端(但在一些對於單片機的實現中卻是基於大端,比如Keil 51C),Java是平台無關的,默認是大端。在網路上傳輸數據普遍採用的都是大端。