Big Endian 和 Little Endian 詳解
一、Endian的起源
在各種計算機體系結構中,對於位元組、字等的儲存機制有所不同,因而引發了計算機通訊領域中一個很重要的問題,即通訊雙方交流的資訊單元(位元、位元組、字、雙字等等)應該以什麼樣的順序進行傳送。如果不達成一致的規則,通訊雙方將無法進行正確的編/譯碼從而導致通訊失敗。
1980年,Danny Cohen在其著名的論文”On Holy Wars and a Plea for Peace”中為了平息一場關於在訊息中位元組該以什麼樣的順序進行傳送的爭論而引用了該詞。該文中,Cohen非常形象貼切地把支援從一個訊息序列的最高位開始傳送的那夥人叫做Big-Endians,支援從最低位開始傳送的相對應地叫做Little-Endians。此後Endian這個詞便隨著這篇論文而被廣為採用。
二、位元組序之Little-Endian&Big-Endian
首先,明確一點,咱們接觸到的物理單元最小都是位元組;因此,無論是big endian,還是little endian,都是針對多個位元組的序列而言的;當然,在通訊領域中,這裡往往是bit,不過原理也是類似的,稍後我會介紹。
對於位元組序列的儲存格式,目前有兩大陣營,那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列採用big endian方式儲存資料,而x86系列則採用little endian方式儲存資料。那麼究竟什麼是big endian,什麼又是little endian呢?
1)Little-endian:將低序位元組儲存在起始地址(低位編址)
2)Big-endian:將高序位元組儲存在起始地址(高位編址)
舉個例子:
如果我們將0x1234abcd寫入到以0x0000開始的記憶體中,則結果為;
address | big-endian | little-endian |
---|---|---|
0x0000 | 0x12 | 0xcd |
0x0001 | 0x34 | 0xab |
0x0002 | 0xab | 0x34 |
0x0003 | 0xcd | 0x12 |
注:每個地址存1個位元組,2位16進位制數是1個位元組(0xFF=11111111);
為什麼要注意位元組序的問題呢?你可能這麼問。當然,如果你寫的程式只在單機環境下面執行,並且不和別人的程式打交道,那麼你完全可以忽略位元組序的存在。
但是,如果你的程式要跟別人的程式產生互動呢?在這裡我想說說兩種語言。C/C++語言編寫的程式裡資料儲存順序是跟編譯平臺所在的CPU相關的,而JAVA編寫的程式則唯一採用big endian方式來儲存資料。
試想,如果你用C/C++語言在x86平臺下編寫的程式跟別人的JAVA程式互通時會產生什麼結果?就拿上面的0x12345678來說,你的程式傳遞給別人的一個數據,將指向0x12345678的指標傳給了JAVA程式,由於JAVA採取big endian方式儲存資料,很自然的它會將你的資料翻譯為0x78563412。什麼?竟然變成另外一個數字了?是的,就是這種後果。因此,在你的C程式傳給JAVA程式之前有必要進行位元組序的轉換工作。
無獨有偶,所有網路協議也都是採用big endian的方式來傳輸資料的。所以有時我們也會把big endian方式稱之為網路位元組序。當兩臺採用不同位元組序的主機通訊時,在傳送資料之前都必須經過位元組序的轉換成為網路位元組序後再進行傳輸。
目前應該little endian是主流,因為在資料型別轉換的時候(尤其是指標轉換)不用考慮地址問題。
三、位元序之Little-Endian&Big-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位元的數的話,由於這個數在littel endian方儲存時佔了4個位元組,而網路傳輸是以位元組為單位進行的,little endian方的CPU讀出第一個位元組後傳送,實際上這個位元組是原數的LSB,到了接收方反倒成了MSB從而發生混亂。