go 语言大小端字节序的问题
我们一般把字节(byte)当作是数据的最小单位。当然,其实一个字节中还包含8个bit (bit = binary digit)。 在这样的CPU中,总是以4字节对齐的方式来读取或写入内存, 那么同样这4个字节的数据是以什么顺序保存在内存中的呢?我们下面详细探讨一下。
字节序包括:大端序和小端序。
而所谓大端序(big endian),便是指其“最高有效位(most significant byte)”落在低地址上的存储方式。
而对于小端序(little endian)来说就正好相反了,它把“最低有效位(least significant byte)”放在低地址上。
go处理字节序接口
Go中处理大小端序的代码位于 encoding/binary ,包中的全局变量BigEndian用于操作大端序数据,LittleEndian用于操作小端序数据,这两个变量所对应的数据类型都实行了ByteOrder接口
type ByteOrder interface {
Uint16([]byte) uint16
Uint32([]byte) uint32
Uint64([]byte) uint64
PutUint16([]byte, uint16)
PutUint32([]byte, uint32)
PutUint64([]byte, uint64)
String() string
}
从函数的命名也可了解到前三个是读数据 中间三个是写数据
当类型不满足要求是我们也可以按照go语言的强转格式进行强转
入门demo
package main
import (
"encoding/binary"
"fmt"
)
func testBigEndian() {
// 0000 0000 0000 0000 0000 0001 1111 1111
var testInt int32 = 256
fmt.Printf("%d use big endian: \n", testInt)
var testBytes []byte = make([]byte, 4)
binary.BigEndian.PutUint32(testBytes, uint32(testInt))
fmt.Println("int32 to bytes:", testBytes)
convInt := binary.BigEndian.Uint32(testBytes)
fmt.Printf("bytes to int32: %d\n\n", convInt)
}
func testLittleEndian() {
// 0000 0000 0000 0000 0000 0001 1111 1111
var testInt int32 = 256
fmt.Printf("%d use little endian: \n", testInt)
var testBytes []byte = make([]byte, 4)
fmt.Println("int32 to bytes:", testBytes)
convInt := binary.LittleEndian.Uint32(testBytes)
fmt.Printf("bytes to int32: %d\n\n", convInt)
}
func main() {
testBigEndian()
testLittleEndian()
}
运行结果如下
但有时候这样做未必会满足我们要求,因为我们编程一般只是做了中间的工作要按照已经封装好的模块之上进行开发。如果发现写入的int32来存储的ipv4发过去总是反的可以仔细研究一下下方代码
package main
import (
"encoding/binary"
"fmt"
)
func main() {
var testInt int32 = -1062731517
fmt.Printf("%d use big endian: \n", testInt)
var testBytes []byte = make([]byte, 4)
binary.BigEndian.PutUint32(testBytes, uint32(testInt))
fmt.Println("int32 to bytes:", testBytes)
convInt := binary.LittleEndian.Uint32(testBytes)
}
运行结果如下图
package main
import (
"encoding/binary"
"fmt"
)
func main() {
var testInt int32 = -1062731517
fmt.Printf("%d use little endian: \n", testInt)
var testBytes []byte = make([]byte, 4)
binary.LittleEndian.PutUint32(testBytes, uint32(testInt))
fmt.Println("int32 to bytes:", testBytes)
convInt := binary.BigEndian.Uint32(testBytes)
fmt.Println(convInt)
}
运行结果如下图
总结
为了增强程序的兼容性,我们在开发跨服务器的TCP服务时,每次发送和接受数据都要进行转换,这样做的目的是保证代码在任何计算机上执行时都能达到预期的效果。
参考来自 http://lihaoquan.me/2016/11/5/golang-byteorder.html