字节序——Big Endian和Little Endian
Big Endian和Little Endian
- 一、Endian 的起源
- 二、字節序之 Little-Endian&Big-Endian
- 三、為什么要注意字節序
- 四、網絡序和主機序
- 五、Go 中的字節序
一、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 呢?
-
Little-endian:將低序字節存儲在起始地址(低位編址)
-
Big-endian:將高序字節存儲在起始地址(高位編址)
案例:
注:每個地址存 1 個字節,2 位 16 進制數是 1 個字節(0xFF=11111111)
上面的圖已經夠直觀了。也就是說:
- Big Endian 是指低地址端 存放 高位字節。
- Little Endian 是指低地址端 存放 低位字節。
各自的優勢:
- Big Endian:符號位的判定固定為第一個字節,容易判斷正負。
- Little Endian:長度為 1,2,4 字節的數,排列方式都是一樣的,數據類型轉換非常方便。
三、為什么要注意字節序
如果你寫的程序只在單機環境下面運行,并且不和別人的程序打交道,那么你完全可以忽略字節序的存在。
但是,如果你的程序要跟別人的程序產生交互呢? 比如,當一個 C/C++ 的程序要與一個 Java 程序交互時:
-
C/C++語言編寫的程序里數據存儲順序是跟編譯平臺所在的 CPU 相關的,而現在比較普遍的 x86 處理器是 Little Endian
-
JAVA 編寫的程序則唯一采用 Big Endian 方式來存儲數據
-
Go 編寫的程序可自主選擇使用哪個字節序,有開發者來約定
試想,如果你的 C/C++程序將變量 a = 0x12345678 的首地址傳遞給了 Java 程序,由于 Java 采取 Big Endian 方式存儲數據,很自然的它會將你的數據翻譯為 0x78563412。顯然,問題就出現了!!!
另外,網絡傳輸一般采用 Big Endian,也被稱之為網絡字節序,或網絡序。當兩臺采用不同字節序的主機通信時,在發送數據之前都必須經過字節序的轉換成為網絡字節序后再進行傳輸。
四、網絡序和主機序
網絡字節序: TCP/IP 各層協議將字節序定義為 Big Endian,因此 TCP/IP 協議中使用的字節序是大端序。
主機字節序: 整數在內存中存儲的順序,現在 Little Endian 比較普遍。(不同的 CPU 有不同的字節序)
在進行網絡通信時 通常需要調用相應的函數進行主機序和網絡序的轉換。
五、Go 中的字節序
Go 中處理大小端序的代碼位于 encoding/binary包,其中全局變量 BigEndian 用于操作大端序數據,LittleEndian 用于操作小端序數據,這兩個變量所對應的數據類型都實行了 ByteOrder 接口:
type ByteOrder interface {Uint16([]byte) uint16Uint32([]byte) uint32Uint64([]byte) uint64PutUint16([]byte, uint16)PutUint32([]byte, uint32)PutUint64([]byte, uint64)String() string}其中,前三個方法用于讀取數據,后三個方法用于寫入數據。
大家可能會注意到,上面的方法操作的都是無符號整型,如果我們要操作有符號整型的時候怎么辦呢?很簡單,強制轉換就可以了,比如這樣:
func PutInt32(b []byte, v int32) {binary.BigEndian.PutUint32(b, uint32(v)) }為了程序的兼容,我們在開發跨服務器的 TCP 服務時,每次發送和接受數據都要進行轉換,這樣做的目的是保證代碼在任何計算機上執行時都能達到預期的效果。
參考:
go 語言的字節序
Big Endian 和 Little Endian 詳解
字節序:Big Endian 和 Little Endian
總結
以上是生活随笔為你收集整理的字节序——Big Endian和Little Endian的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 可以不用在应用中实现苹果登录了
- 下一篇: 认知天性读书笔记