大端模式与小端模式
一、引子
在各種計算機體系結構中,對于字節、字等的存儲機制有所不同,因而引發了
計算機通信領域中一個很重要的問題,即通信雙方交流的信息單元(比特、字節、
字、雙字等等)應該以什么樣的順序進行傳送。如果不達成一致的規則,通信雙方
將無法進行正確的編/譯碼從而導致通信失敗。目前在各種體系的計算機中通常采
用的字節存儲機制主要有兩種:
big-edian和little-endian。本文簡要描述這兩種存儲機制的來歷、特點和區別。
為了敘述方便,下面先對本文中將要用到的兩個術語做簡單的定義。
1、MSB
MSB是Most Significant Bit/Byte的首字母縮寫,通常譯為最重要的位或者最
重要的字節。它通常用來表明在一個bit序列(如一個byte是8個bit組成的一個序
列)或者一個byte序列(如word是兩個byte組成的一個序列)中對整個序列取值影
響最大的那個bit/byte。
2、LSB
LSB是Least Significant Bit/Byte的首字母縮寫,通常譯為最不重要的位或
者最不重要的字節。它通常用來表明在一個bit序列(如一個byte是8個bit組成的
一個序列)或者一個byte序列(如word是兩個byte組成的一個序列)中對整個序
列取值影響最小的那個bit/byte。
?
二、endian的由來
1、Definition
endian: The ordering of bytes in a multi-byte number.
定義:在計算機系統體系結構中用來描述在多字節數中各個字節的存儲順序。
?
2、Etymology
The term comes from Swift's "Gulliver's Travels" via the famous paper
"On Holy Wars and a Plea for Peace" by Danny Cohen, USC/ISI IEN 137,
1980-04-01.
The Lilliputians, being very small, had correspondingly small political
problems. The Big-Endian and Little-Endian parties debated over whether
soft-boiled eggs should be opened at the big end or the little end.[From:
Free On-Line Dictionary Of Computing or Jargon File]
詞源:據Jargon File記載,endian這個詞來源于Jonathan
Swift在1726年寫的諷刺小說 "Gulliver's Travels"(《格利佛游記》)。該小說
在描述Gulliver暢游小人國時碰到了如下的一個場景。在小人國里的小人因為非常
小(身高6英寸)所以總是碰到一些意想不到的問題。有一次因為對水煮蛋該從大的
一端(Big-End)剝開還是小的一端(Little-End)剝開的爭論而引發了一場戰爭,
并形成了兩支截然對立的隊伍:支持從Big-End剝開的人Swift就稱作Big-Endians
而支持從Little-End剝開的人就稱作Little-Endians……(后綴ian表明的就是支持
某種觀點的人:-)。Endian這個詞由此而來。
1980年,Danny Cohen在其著名的論文"On Holy Wars and a Plea for Peace"
中為了平息一場關于在消息中字節該以什么樣的順序進行傳送的爭論而引用了該詞。
該文中,Cohen非常形象貼切地把支持從一個消息序列的MSB開始傳送的那伙人叫做
Big-Endians,支持從LSB開始傳送的相對應地叫做Little-Endians。此后Endian這
個詞便隨著這篇論文而被廣為采用。
?
三、各種endian
1、big-endian
A computer architecture in which, within a given multi-byte numeric
representation, the most significant byte has the lowest address (the
word is stored "big-end-first").
Most processors, including the IBM 370 family, the PDP-10, the
Motorola microprocessor families, and most of the various RISC designs
current in mid-1993, are big-endian. [From: Free On-Line Dictionary Of
Computing or Jargon File]
big-endian:計算機體系結構中一種描述多字節存儲順序的術語,在這種機制
中最重要字節(MSB)存放在最低端的地址上。采用這種機制的處理器有IBM3700系
列、PDP-10、Mortolora微處理器系列和絕大多數的RISC處理器。
?
?
?
+----------+
| 0x34 |<-- 0x00000021
+----------+
| 0x12 |<-- 0x00000020
+----------+
圖1:雙字節數0x1234以big-endian的方式存在起始地址0x00000020中
?
在Big-Endian中,對于bit序列中的序號編排方式如下(以雙字節數0x8B8A為
例):
bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+----------------------------------------+
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+----------------------------------------+
^ 0x8B 0x8A ^
MSB LSB
圖2:Big-Endian的bit序列編碼方式
?
注1:通常在TCP/IP協議棧所說的網絡序(Network Order)就是遵循Big-Endian
規則。在TCP/IP網絡通信中,通信雙方把消息按照如圖2的方式進行編碼,然后按
從MSB(Bit0)到LSB的順序在網絡上傳送。
2、little-endian
A computer architecture in which, within a given
16- or 32-bit word,bytes at lower addresses have lower significance (the
word is stored "little-end-first"). The PDP-11 and VAX families of
computers and Intel microprocessors and a lot of communications and
networking hardware are little-endian.
The term is sometimes used to describe the ordering of units other
than bytes; most often, bits within a byte. [From: Free On-Line Dictionary
Of Computing or Jargon File]
little-endian:計算機體系結構中一種描述多字節存儲順序的術語,在這種機
制中最不重要字節(LSB)存放在最低端的地址上。采用這種機制的處理器有PDP-11、
VAX、Intel系列微處理器和一些網絡通信設備。該術語除了描述多字節存儲順序外
還常常用來描述一個字節中各個比特的排放次序。
?
+----------+
| 0x12 |<-- 0x00000021
+----------+
| 0x34 |<-- 0x00000020
+----------+
圖3:雙字節數0x1234以little-endian的方式存在起始地址0x00000020中
?
在Little-Endian中,對于bit序列中的序號編排和Big-Endian剛好相反,其方
式如下(以雙字節數0x8B8A為例):
?
bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+-----------------------------------------+
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+-----------------------------------------+
^ 0x8B 0x8A ^
MSB LSB
圖4:Little-Endian的bit序列編碼方式
?
注2:通常我們說的主機序(Host Order)就是遵循Little-Endian規則。所以
當兩臺主機之間要通過TCP/IP協議進行通信的時候就需要調用相應的函數進行主機
序(Little-Endian)和網絡序(Big-Endian)的轉換。
注3:正因為這兩種機制對于同一bit序列的序號編排方式恰恰相反,所以《現
代英漢詞典》中對MSB的翻譯為“最高有效位”欠妥,故本文定義為“最重要的bit
/byte”。
?
3、middle-endian:
Neither big-endian nor little-endian. Used of
perverse byte orders such as 3-4-1-2 or 2-1-4-3, occasionally found in
the packed decimal formats of some minicomputer manufacturers.[From:
Free On-Line Dictionary Of Computing or Jargon File]
middle-endian:除了big-endian和little-endian之外的多字節存儲順序就是
middle-endian,比如以4個字節為例:象以3-4-1-2或者2-1-4-3這樣的順序存儲的
就是middle-endian。這種存儲順序偶爾會在一些小型機體系中的十進制數的壓縮格
式中出現。
四、收尾
要詳細解釋這兩種編碼順序已經超出本文所涉及的內容,如果你有興趣的話可
以參考上面提及的Danny Cohen的論文("On Holy Wars and a Plea for Peace"),
該論文詳細的描述了這兩種編碼順序的歷史、所基于的數學理論和各自擁護者爭論
的焦點等知識,絕對可以大飽你打破沙鍋問到底的內心需要。
?
?
什么是字節序?
?? 字節序,顧名思義字節的順序,再多說兩句就是大于一個字節類型的數據在內存中的存放順序(一個字節的數據當然就無需談順序的問題了)。其實大部分人在實際的開發中都很少會直接和字節序打交道。唯有在跨平臺以及網絡程序中字節序才是一個應該被考慮的問題。在所有的介紹字節序的文章中都會提到字節序分為兩類:Big-Endian和Little-Endian。引用標準的Big-Endian和Little-Endian的定義如下:
a) Little-Endian就是低位字節排放在內存的低地址端,高位字節排放在內存的高地址端。
b) Big-Endian就是高位字節排放在內存的低地址端,低位字節排放在內存的高地址端。
c) 網絡字節序:TCP/IP各層協議將字節序定義為Big-Endian,因此TCP/IP協議中使用的字節序通常稱之為網絡字節序。
PS:有些文章中稱低位字節為最低有效位,高位字節為最高有效位。
Big endian means that the most significant byte of any multibyte data field is stored at the lowest memory address, which is also the address of the larger field.
Little endian means that the least significant byte of any multibyte data field is stored at the lowest memory address, which is also the address of the larger field.
?? 什么是高/低地址端 什么是高/低字節
?? 首先我們要知道我們C程序映像中內存的空間布局情況:在《C專家編程》中或者《Unix環境高級編程》中有關于內存空間布局情況的說明,大致如下圖:
----------------------- 最高內存地址 0xffffffff
| 棧底
.
. 棧
.
棧頂
-----------------------
|
|
/|/
NULL (空洞)
/|/
|
|
-----------------------
堆
-----------------------
未初始化的數據
----------------(統稱數據段)
初始化的數據
-----------------------
正文段(代碼段)
----------------------- 最低內存地址 0x00000000
以上圖為例如果我們在棧上分配一個unsigned char buf[4],那么這個數組變量在棧上是如何布局的呢?看下圖:
棧底 (高地址)
----------
buf[3]
buf[2]
buf[1]
buf[0]
----------
棧頂 (低地址)
現在我們弄清了高/低地址,接著考慮高/低字節。如果我們有一個32位無符號整型0x12345678,那么高位是什么,低位又是什么呢?其實很簡單。在十進制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進制也是如此。就拿 0x12345678來說,從高位到低位的字節依次是0x12、0x34、0x56和0x78。
高/低地址端和高/低字節都弄清了。我們再來回顧一下Big-Endian和Little-Endian的定義,并用圖示說明兩種字節序:
以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) -- 低位
--------------
棧頂 (低地址)
?? 現有的平臺上Intel的X86采用的是Little-Endian,而像Sun的SPARC采用的就是Big-Endian。那么在跨平臺或網絡程序中如何實現字節序的轉換呢?這個通過C語言的移位操作很容易實現,例如下面的宏:
#if defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
#define htons(A)?? (A)
#define htonl(A) ??? (A)
#define ntohs(A)?? (A)
#define ntohl(A)??? (A)
#elif defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
#define htons(A) ??? ((((uint16)(A) & 0xff00) >> 8) | /
?????????????????????????????? (((uint16)(A) & 0x00ff) << 8))
#define htonl(A) ??? ((((uint32)(A) & 0xff000000) >> 24) | /
????????????????????????????? (((uint32)(A) & 0x00ff0000) >> 8) | /
????????????????????????????? (((uint32)(A) & 0x0000ff00) << 8) | /
????????????????????????????? (((uint32)(A) & 0x000000ff) << 24))
#define ntohs htons
#define ntohl htohl
#else
#error "Either BIG_ENDIAN or LITTLE_ENDIAN must be #defined, but not both."
#endif
?
?? 如何檢查處理器是big-endian還是little-endian?
?? 由于聯合體union的存放順序是所有成員都從低地址開始存放,利用該特性就可以輕松地獲得了CPU對內存采用Little-endian還是Big-endian模式讀寫。例如:
?? int checkCPUendian(){
??????? union {
???????????? unsigned int a;
???????????? unsigned char b;????????????
??????? }c;
??????? c.a = 1;
??????? return (c.b == 1);???????
?? }?? /*return 1 : little-endian, return 0:big-endian*/
總結
- 上一篇: 众安小贷99元会员是什么意思
- 下一篇: 你我贷一般几点到账