先上結論 , 咱們默認人讀字節時 , 從右往左讀 , 這就是小端序 , 因為計算機處理的時候會從低位到高位處理 , 和人的習慣正好相反
本文轉自公眾號:網管daobidao
字節序,又稱端序或尾序(英語中用單詞:Endianness 表示),在計算機領域中,指電腦內存中或在數字通信鏈路中,占用多個字節的數據的字節排列順序。
在幾乎所有的平台上,多字節對象都被存儲為連續的字節序列。例如在 Go 語言中,一個類型為int的變量x地址為0x100,那么其指針&x的值為0x100。且x的四個字節將被存儲在內存的0x100, 0x101, 0x102, 0x103位置。
字節的排列方式有兩個通用規則:
- 大端序(Big-Endian)將數據的低位字節存放在內存的高位地址,高位字節存放在低位地址。這種排列方式與數據用字節表示時的書寫順序一致,符合人類的閱讀習慣。
- 小端序(Little-Endian),將一個多位數的低位放在較小的地址處,高位放在較大的地址處,則稱小端序。小端序與人類的閱讀習慣相反,但更符合計算機讀取內存的方式,因為CPU讀取內存中的數據時,是從低地址向高地址方向進行讀取的。
上面的文字描述有點抽象,我們拿一個例子來解釋一下字節排列時的大端序和小端序。
在內存中存放整型數值168496141 需要4個字節,這個數值的對應的16進制表示是0X0A0B0C0D,這個數值在用大端序和小端序排列時的在內存中的示意圖如下:

為何要有字節序
很多人會問,為什么會有字節序,統一用大端序不行嗎?答案是,計算機電路先處理低位字節,效率比較高,因為計算都是從低位開始的。所以,計算機的內部處理都是小端字節序。在計算機內部,小端序被廣泛應用於現代 CPU 內部存儲數據;而在其他場景,比如網絡傳輸和文件存儲則使用大端序。
Go語言對字節序的處理
Go 語言存儲數據時的字節序依賴所在平台的 CPU,處理大小端序的代碼位於 encoding/binary ,包中的全局變量BigEndian用於操作大端序數據,LittleEndian用於操作小端序數據,這兩個變量所對應的數據類型都實現了ByteOrder接口。
package main import ( "encoding/binary" "fmt" "unsafe" ) const INT_SIZE = int(unsafe.Sizeof(0)) //64位操作系統,8 bytes //判斷我們系統中的字節序類型 func systemEdian() { var i = 0x01020304 fmt.Println("&i:",&i) bs := (*[INT_SIZE]byte)(unsafe.Pointer(&i)) if bs[0] == 0x04 { fmt.Println("system edian is little endian") } else { fmt.Println("system edian is big endian") } fmt.Printf("temp: 0x%x,%v\n",bs[0],&bs[0]) fmt.Printf("temp: 0x%x,%v\n",bs[1],&bs[1]) fmt.Printf("temp: 0x%x,%v\n",bs[2],&bs[2]) fmt.Printf("temp: 0x%x,%v\n",bs[3],&bs[3]) } //測試大端序 func testBigEndian() { var testInt int32 = 0x01020304 fmt.Printf("%d use big endian: \n", testInt) testBytes := make([]byte, 4) binary.BigEndian.PutUint32(testBytes, uint32(testInt)) fmt.Println("int32 to bytes:", testBytes) fmt.Printf("int32 to bytes: %x \n", testBytes) convInt := binary.BigEndian.Uint32(testBytes) fmt.Printf("bytes to int32: %d\n\n", convInt) } //測試小端序 func testLittleEndian() { var testInt int32 = 0x01020304 fmt.Printf("%x use little endian: \n", testInt) testBytes := make([]byte, 4) binary.LittleEndian.PutUint32(testBytes, uint32(testInt)) fmt.Printf("int32 to bytes: %x \n", testBytes) convInt := binary.LittleEndian.Uint32(testBytes) fmt.Printf("bytes to int32: %d\n\n", convInt) } func main() { systemEdian() fmt.Println("") testBigEndian() testLittleEndian() }
&i: 0xc000084000 system edian is little endian temp: 0x4,0xc000084000 temp: 0x3,0xc000084001 temp: 0x2,0xc000084002 temp: 0x1,0xc000084003 16909060 use big endian: int32 to bytes: [1 2 3 4] int32 to bytes: 01020304 bytes to int32: 16909060 1020304 use little endian: int32 to bytes: 04030201 bytes to int32: 16909060
大端序是從左往右符合人的習慣 , 小端序是從右往左 , 不符合人的習慣 , 上面的代碼 , 第一個是顯示當前系統是大端序還是小端序
后面兩個是存儲int32 的兩種方式
