不同的CPU有不同的字節(jié)序類型,這些字節(jié)序是指整數在內存中保存的順序。分為小端格式和大端格式(Little-Endian&Big-Endian):
- Little-endian:將低位字節(jié)存儲在起始地址(低位編址)
- Big-endian:將高位字節(jié)存儲在起始地址(高位編址)
比如0x1234; 低8位是34,高8位是12;如果它們分配的內存其實地址是0x0001,
那么如果是大端存儲,那么0x0001內存低位地址存放高位字節(jié)12;如果是小端存儲,那么0x0001內存低位地址存放低位字節(jié)34,0x0002存放12。
一、歷史由來
據Jargon File記載,endian這個詞來源于Jonathan Swift在1726年寫的諷刺小說 "Gulliver's Travels"(《格利佛游記》)。該小說在描述Gulliver暢游小人國時碰到了如下的一個場景。在小人國里的小人因為非常?。ㄉ砀?英寸)所以總是碰到一些意想不到的問題。有一次因為對水煮蛋該從大的一端(Big-End)剝開還是小的一端(Little-End)剝開的爭論而引發(fā)了一場戰(zhàn)爭,并形成了兩支截然對立的隊伍:支持從大的一端剝開的人Swift就稱作Big-Endians,而支持從小的一端剝開的人就稱作Little-Endians......(后綴ian表明的就是支持某種觀點的人)。
1980年,Danny Cohen在其著名的論文"On Holy Wars and a Plea for Peace"中為了平息一場關于在消息中字節(jié)該以什么樣的順序進行傳送的爭論而引用了該詞。該文中,Cohen非常形象貼切地把支持從一個消息序列的最高位開始傳送的那伙人叫做Big-Endians,支持從最低位開始傳送的相對應地叫做Little-Endians。此后Endian這個詞便隨著這篇論文而被廣為采用。
二、深入理解
little endian和big endian是表示計算機字節(jié)順序的兩種格式,所謂的字節(jié)順序指的是長度跨越多個字節(jié)的數據的存放形式.
假設從地址0x00000000開始的一個字中保存有數據0x1234abcd,那么在兩種不同的內存順序的機器上從字節(jié)的角度去看的話分別表示為:
- little endian:在內存中的存放順序是0x00000000-0xcd,0x00000001-0xab,0x00000002-0x34,0x00000003-0x12
- big endian:在內存中的存放順序是0x00000000-0x12,0x00000001-0x34,0x00000002-0xab,0x00000003-0xcd
需要特別說明的是,以上假設機器是每個內存單元以8位即一個字節(jié)為單位的. 簡單的說,little endian把低字節(jié)存放在內存的低位;而big endian將低字節(jié)存放在內存的高位.
現在主流的CPU,intel系列的是采用的little endian的格式存放數據,而motorola系列的CPU采用的是big endian.
三、背景MSB/LSB
比如: int x, 它的地址為0x100。 那么它占據了內存中的Ox100, 0x101, 0x102, 0x103這四個字節(jié)(32位系統(tǒng),所以int占用4個字節(jié))。
上面只是內存字節(jié)組織的一種情況: 多字節(jié)對象在內存中的組織有一般有兩種約定。 考慮一個W位的整數。它的各位表達如下:
Xw-1, Xw-2, ... , X1, X0,它的
MSB (Most Significant Byte, 最高有效字節(jié))為 Xw-1, Xw-2, ... Xw-8;
LSB (Least Significant Byte, 最低有效字節(jié))為 X7,X6,..., X0。
其余的字節(jié)位于MSB, LSB之間。
這就引出了大端(Big Endian)與小端(Little Endian)的問題。如果LSB在MSB前面, 既LSB是低地址, 則該機器是小端; 反之則是大端。
對于數據中跨越多個字節(jié)的對象, 我們必須為它建立這樣的約定:
- 它的地址是多少?
- 它的字節(jié)在內存中是如何組織的?
對于跨越多個字節(jié)的對象,一般它所占的字節(jié)都是連續(xù)的,它的地址等于它所占字節(jié)最低地址。(鏈表可能是個例外, 但鏈表的地址可看作鏈表頭的地址)。
程序判斷大端還是小端
- C/C++
bool IsBig_Endian()
//如果字節(jié)序為big-endian,返回true;
//反之為 little-endian,返回false
{
unsigned short test = 0x1122;
if(*( (unsigned char*) &test ) == 0x11)
return TRUE;
else
return FALSE;
}//IsBig_Endian()
#include <stdio.h>
int main()
{
union ut{
short s;
char c[2];
}u;
if(sizeof(short) == 2)
{
u.s = 0x0102;
if(u.c[0] == 1 && u.c[1] == 2)
{
printf("big enidan.\n");
} else if(u.c[0] == 2 && u.c[1] == 1)
{
printf("little endian.\n");
}
}
return 0;
}
- Java接口
import java.nio.ByteOrder;
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
System.out.println("BIG_ENDIAN");
} else {
System.out.println("LITTLE_ENDIAN");
}
}