将 []byte 转为 Little/Big-Endian 有符号整数还是浮点数?

Posted

技术标签:

【中文标题】将 []byte 转为 Little/Big-Endian 有符号整数还是浮点数?【英文标题】:Go []byte to Little/Big-Endian Signed Integer or Float? 【发布时间】:2016-04-14 13:27:42 【问题描述】:

我能够将[]byte 转换为无符号整数:

a := binary.LittleEndian.Uint16(sampleA)
b := binary.BigEndian.Uint32(sampleB)

这利用了 Go 包 https://golang.org/src/encoding/binary/binary.go 中的 BigEndian 和 LittleEndian 类型。

这提供了Uint16(),但是没有等效的Int16()Float32()

有什么想法为什么不呢?还有,这应该怎么做?

【问题讨论】:

【参考方案1】:

将数字类型转换为一系列字节([]byte),反之亦然,这与endianness 有关。如何解释结果完全取决于您。

您只需要组装一个 16 位、32 位或 64 位的值,一旦完成,您就可以根据需要解释结果。

例如,如果您已经有一个uint16 值,要将其用作有符号值,您只需要一个类型conversion,因为uint16int16 的内存布局是相同的(转换从uint16int16 不会改变内存表示,只是类型):

a := binary.LittleEndian.Uint16(sampleA)
// If you need int16:
a2 := int16(a)

同样:

a := binary.LittleEndian.Uint64(sampleA)
// If you need int64:
a2 := int64(a)

使用 uint -> float 转换的情况稍微复杂一些,因为使用简单的类型转换会尝试转换数值,而不仅仅是更改类型(因此会更改内存表示)。

对于将无符号整数转换为浮点类型,您可以使用math 包的函数,即math.Float32frombits()math.Float64frombits(),并且对于具有相同内存的相反方向(将浮点值转换为无符号整数)布局:math.Float32bits()math.Float64bits()

例如:

a := binary.LittleEndian.Uint64(sampleA)
// If you need a float64:
a2 := math.Float64frombits(a)

如果您从 math 包中查看这些函数的实现,您会发现内存值/布局没有被操纵,它只是被“查看”为不同的类型,通过使用 unsafe包裹。例如:

func Float32frombits(b uint32) float32  return *(*float32)(unsafe.Pointer(&b)) 

正如 Paul 所提到的,binary 包提供了 Read()Write() 函数来在后台进行这些转换,因此您不需要这样做。

使用相同的“pi”示例进行展示(来自binary.Read() 的文档):

b := []byte0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40

// USING binary.Read()
var pi float64
buf := bytes.NewReader(b)
err := binary.Read(buf, binary.LittleEndian, &pi)
if err != nil 
    fmt.Println("binary.Read failed:", err)

fmt.Println(pi)

// Using LittleEndian.Uint64() and math.Float64frombits()
a := binary.LittleEndian.Uint64(b)
a2 := math.Float64frombits(a)
fmt.Println(a2)

输出(在Go Playground 上试试):

3.141592653589793
3.141592653589793

【讨论】:

【参考方案2】:

ByteOrder 类型提供用于解码二进制值的低级 API。要读取 float64 或其他类型,可以使用binary.Read。 godoc page for the binary package 上有一个example,我在这里复制了它:

var pi float64
b := []byte0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40
buf := bytes.NewReader(b)
err := binary.Read(buf, binary.LittleEndian, &pi)
if err != nil 
    fmt.Println("binary.Read failed:", err)

fmt.Print(pi)

没有用于解码 float16 的函数,因为这不是 Go 中的类型。

【讨论】:

以上是关于将 []byte 转为 Little/Big-Endian 有符号整数还是浮点数?的主要内容,如果未能解决你的问题,请参考以下文章

在java中,如何将byte转为string

java 如何将string src = "ff" 转为 byte[] bt = (byte)0xff

使用unsafe.Pointer将结构体转为[]byte

将 []byte 转为 Little/Big-Endian 有符号整数还是浮点数?

文件读写操作inputStream转为byte[] , 将InputStream写入本地文件

java Object和byte数组互相转换中遇到的问题