【问题标题】:What's a compact way of casting a struct into a byte slice in Go?在 Go 中将结构转换为字节切片的紧凑方法是什么?
【发布时间】:2016-05-30 01:32:04
【问题描述】:

在编写网络代码时,我们经常发现自己从字节切片填充结构以访问对象形式的数据。

让我们来看看这个结构

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 {
    // handle it
}

但是

  • 它使用unsafe

  • 每次转换需要大约 7 行代码(如果我们有数百个不同的数据包会怎样)

  • 不能简单地打包到 Cast(*struct, data) 函数中

  • 无法控制结构填充,如果 go 的编译器决定在网络一端的成员之间添加额外字节怎么办?

  • binary.Read 如果我没记错的话会执行数据复制(这不一定是骗局)


在 C 语言中,网络两端只需要#pragma pack(1),就一种字节序达成一致

最后是PACKETHEAD* pkt = (PACKETHEAD*)dataptr;

我们如何用 Go 实现同样的目标?


祝你有美好的一天, 克里斯

【问题讨论】:

  • @Denzel 这不是重复的,您发布的链接中的答案实际上是我的建议。
  • 没错,这是正确的方法。以 C 方式执行此操作会破坏 Go 的类型安全,因此不提供。
  • @Denzel 好吧,我希望这不是唯一的方法。这就是我问这个问题的原因。
  • 使用像 protobuf 这样的序列化器怎么样?这似乎更安全。

标签: networking go struct casting padding


【解决方案1】:

gopack 的无耻插件,我(和其他人)编写的一个库,用于支持 Go 中的位打包。注意:如果有问题,它会在后台使用不安全的操作。

【讨论】:

  • +1 这实际上是黄金。 Go 开发者应该考虑将你的工作集成到标准包中。一个问题,您的库如何处理填充和对齐?我问是因为服务器是用 Go 编写的,而客户端是用 C 编写的。
  • 它忽略对齐,只打包程序员知道的数据。因此,例如,如果您有 struct{ a, b uint32 },但它与 ab 之间的 4 个字节对齐(即,实际上是 struct{ a, _, b uint32 }),并且您打包成一个 8 字节的切片,那么一切都适合。
  • 与此相关,我什至不确定当您要求的位数少于实际字段的大小时注意对齐意味着什么(例如,打包 7 位意味着什么一个 8 位字段,后跟 4 个字节的填充,然后是 3 位 16 位字段?)。
  • 另外,至于将它添加到标准库,我很欣赏这个建议,但它需要做很多工作才能成为一个合理的建议。也就是说,我总是愿意接受拉取请求;)
猜你喜欢
  • 2017-02-19
  • 1970-01-01
  • 2023-03-23
  • 2017-06-21
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多