在各類計算機體系結構中,對於字節(byte)、字(bit)的存儲機制有所不一樣,於是,引起了計算機通訊領域中一個很重要的問題,即通訊雙方交流的信息單元(比特、字節、字、雙字等等)應該以什麼樣的順序進行傳輸。若是不達成一致的規則,通訊雙方將沒法進行正確的編/譯碼,從而致使通訊失敗。markdown
1980年,丹尼·寇恩(Danny Cohen)在其著名的論文「關於聖戰與和平的呼籲(On Holy Wars and a Plea for Peace)」中,爲了平息一場關於在消息中,字節該以什麼樣的順序進行傳輸的爭論而引用了該詞。該文中,Cohen很是形象貼切地,把支持從一個消息序列的最高位開始傳輸的那夥人叫作Big-Endians,支持從最低位開始傳輸的相應地叫作Little-Endians。此後,Endian這個詞便隨着這篇論文而被廣爲採用。網絡
首先,明確一點,我們接觸到的物理單元最小都是字節;所以,不管是Big-Endian,仍是Little-Endian,都是針對多個字節的序列而言的;固然,在通訊領域中,這裏每每是bit,不過原理也是相似的,稍後咱們會分析。函數
對於字節序列的存儲格式,目前有兩大陣營,那就是摩托羅拉(Motorola)的PowerPC系列和Intel的x86系列CPU。PowerPC採用Big-Endian方式存儲數據,而x86系列則採用Little-Endian方式存儲數據。那麼究竟什麼是Big-Endian,什麼又是Little-Endian呢?oop
舉個例子,若是咱們將0x1234abcd寫入到以0x0000開始的內存中,則結果爲:spa
address | Big-Endian | Little-Endian |
---|---|---|
0x0000 | 0x12 | 0xcd |
0x0001 | 0x34 | 0xab |
0x0002 | 0xab | 0x34 |
0x0003 | 0xcd | 0x12 |
注:每一個地址存一個字節,2位16進制數是一個字節(0xFF = 11111111)。.net
爲何要注意字節序的問題呢?你可能會這麼問。固然,若是你寫的程序只在單機環境下面運行,而且不和別人的程序打交道,那麼你徹底能夠忽略字節序的存在。翻譯
可是,若是你的程序要和別人的程序產生交互呢?在這裏我想說說兩種語言。C/C++語言編寫的程序裏數據存儲順序是跟編譯平臺所在的CPU相關的,而JAVA編寫的程序則惟一採用Big-Endian方式來存儲數據。設計
試想,若是你用C/C++語言在x86平臺(x86平臺採用Little-Endian存儲數據)下編寫的程序跟別人的JAVA程序互通時會產生什麼結果?就拿上面的0x1234abcd來舉例,你的程序傳遞給別人的一個數據,將指向0x1234abcd的指針傳給了JAVA程序,因爲JAVA採起Big-Endian方式存儲數據,很天然的它會將你的數據翻譯爲0xcdab3412。什麼?居然變成另一個數字了?就是這種結果。所以,在你的C程序傳給JAVA程序以前有必要進行字節序的轉換工做。指針
無獨有偶,全部網絡協議也都是採用Big-Endian的方式來傳輸數據的。因此有時候咱們也會把Big-Endian方式稱之爲網絡字節序。當兩臺採用不一樣字節序的主機通訊時,在發送數據以前都必須通過字節序的轉換,成爲網絡字節序後再進行傳輸。code
目前應該Little-Endian是主流,由於在數據類型轉換的時候(尤爲是指針轉換)不用考慮地址問題。
Big-Endian:
基於其存儲特色,符號位在所表示的數據的內存的第一個字節中,便於快速判斷數據的正負和大小(CPU作數值運算時從內存中依順序依次從低位地址到高位地址取數據進行運算,大端就會最早拿到數據的(高字節的)符號位)。
Little-Endian
基於其存儲特色,內存的低地址處存放低字節,因此在強制轉換數據時不須要調整字節的內容(好比,把int---4字節強制轉換成short---2字節,就能夠直接把int數據存儲的前兩個字節給short就行,由於其前兩個字節恰好就是最低的兩個字節,符合轉換邏輯;另外CPU作數值運算時,從內存中依順序依次從低位地址到高位地址取數據進行運算,開始只管取值,最後刷新最高位地址的符號位就行,這樣的運算方式會更高效一些)。
由於兩種模式各有優勢,存在「你有我無,你無我有」的特色,因此造就了不一樣的硬件廠商基於不一樣的效率(角度)考慮,有了不一樣的硬件設計支持,最終造成了計算機各個相關領域目前並無採用統一的字節序,沒有統一標準的現狀。
目前咱們常見的CPU PowerPC、IBM是大端模式,x86是小端模式。ARM既能夠工做在大端模式,也能夠工做在小端模式,通常ARM都默認是小端模式。通常通信協議都採用的是大端模式。
另外,常見文件的字節序以下:
文件類型 | 字節序 |
---|---|
BMP | Little-Endian |
GIF | Little-Endian |
JPEG | Big-Endian |
RTF | Little-Endian |
Adobe PS | Bit-Endian |
但是有朋友仍然會問,CPU存儲一個字節的數據時,其字節內的8個比特之間的順序是否也有Big-Endian和Little-Endian之分呢?或者說是否有比特序的不一樣呢?
實際上,這個比特序是一樣存在的。下面以數字0xB4(10110100)用圖加以說明。
MSB的意思是:全稱爲Most Significant Bit,在二進制數中屬於最高有效位,MSB是最高加權位,與十進制數字中最左邊的一位相似。
LSB的意思是:全稱爲Least Significant Bit,在二進制數中意爲最低有效位,通常來講,MSB位於二進制樹的最左側,LSB位於二進制數的最右側。
Big-Endian:
MSB------------------------>LSB
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
複製代碼
Little-Endian:
LSB-------------------------->MSB
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
複製代碼
實際上,因爲CPU存儲數據操做的最小單位是一個字節,其內部的比特序是什麼樣的,對咱們的程序來講是一個黑盒子。也就是說,你給我一個指向0xB4這個數的指針,對於Big-Endian方式的CPU來講,它是從左往右依次讀取這個數的8個比特;而對於Little-Endian方式的CPU來講,則正好相反,是從右往左依次讀取這個數的8個比特。而咱們的程序經過這個指針訪問後獲得的數就是0xB4,字節內部的比特序對於程序來講是不可見的,其實這點對於單機上的字節序來講也是同樣的。
那麼可能有朋友又會問了,若是時網絡傳輸呢?會不會出問題?是否是也要經過什麼函數轉換一個比特序?嗯,這個問題提的很好。假設Little-Endian方式的CPU要傳給Big-Endian方式CPU一個字節的話,其自己在傳輸以前會在本地就讀出這個8比特的數,而後再按照網絡字節序的順序來傳輸這8個比特,這樣的話到了接收端不會出現任何問題。而假如要傳輸一個32比特的數的話,因爲這個數在Little-Endian方存儲時佔了4個字節,而網絡傳輸是以字節爲單位進行的,Little-Endian方的CPU讀出第一個字節後發送,實際上這個字節是原數的LSB,到了接收方反倒成了MSB,從而發生混亂。
參考資料: