[操作系統] 字節序中的大端序和小端序的區別


先上結論 , 咱們默認人讀字節時 , 從右往左讀 , 這就是小端序 , 因為計算機處理的時候會從低位到高位處理 , 和人的習慣正好相反

本文轉自公眾號:網管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 的兩種方式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM