What's a compact way of casting a struct into a byte slice in Go?

huangapple go评论76阅读模式
英文:

What's a compact way of casting a struct into a byte slice in Go?

问题

在编写网络代码时,我们经常需要从字节片段中填充结构体,以便以对象的形式访问数据。

让我们以这个结构体为例:

type PACKETHEAD struct {
    Type uint16
    Size uint16
    Hash uint32
}

以及一个以某种方式填充了数据的字节片段:

data := make([]byte, 1024)

我的解决方案是:

var pkthead PACKETHEAD
pktsiz := unsafe.Sizeof(pkthead)
pktbuf := bytes.NewReader(buf[:pktsiz])
err = binary.Read(pktbuf, binary.BigEndian, &pkthead)
if err != nil {
    // 处理错误
}

但是:

  • 它使用了 unsafe
  • 每次转换都需要大约 7 行代码(如果有数百个不同的数据包怎么办)
  • 不能简单地打包到一个 Cast(*struct, data) 函数中
  • 无法控制结构体的填充方式,如果 Go 的编译器决定在网络的某一端在成员之间添加额外的字节会怎么样?
  • 如果我没记错的话,binary.Read 会执行数据拷贝(这不一定是缺点)

在 C 语言中,我们只需在网络的两端使用 #pragma pack(1),并达成一致的字节序,最后使用 PACKETHEAD* pkt = (PACKETHEAD*)dataptr;

我们如何在 Go 中实现相同的功能呢?


祝您有愉快的一天,
Kris

英文:

When writing network code we often find ourselves populating structs from byte slices to access the data in form of an object.

Let's take this struct

type PACKETHEAD struct {
    Type uint16
    Size uint16
    Hash uint32
}

and a byte slice that has been somehow populated with data

data := make([]byte, 1024)

My solution would be to

var pkthead PACKETHEAD
pktsiz := unsafe.Sizeof(pkthead)
pktbuf := bytes.NewReader(buf[:pktsiz])
err = binary.Read(pktbuf, binary.BigEndian, &pkthead)
if err != nil {
    // handle it
}

But

  • It uses unsafe

  • Requires ~7 lines of code for every cast (what if we had hundreds of different packets)

  • Can't be trivially packed into a Cast(*struct, data) function

  • No control over struct padding, what If go's compiler decides to add extra bytes in between members on one end of a network?

  • binary.Read performs a data copy if I'm not mistaken (this isn't necessarily a con)


In C one would just #pragma pack(1) on both network ends, agree on one type of endianess

and finally PACKETHEAD* pkt = (PACKETHEAD*)dataptr;

How can we achieve the same thing with Go?


Have a nice day,
Kris

答案1

得分: 3

gopack是一个我(和其他人)编写的用于在Go语言中支持位打包的库。注意:它在底层使用了不安全的操作,如果这是一个问题的话。

英文:

Shameless plug for gopack, a library I (and others) wrote to support bitpacking in Go. Note: it uses unsafe operations under the hood, if that's a problem.

huangapple
  • 本文由 发表于 2016年2月18日 11:06:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/35472062.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定