转换struct和byte数组之间的转换

Shr*_*tre 8 struct casting go memcpy

我正在Go中编写一个客户端 - 服务器应用程序.我想在Go中执行类似C的类型转换.

比如Go

type packet struct {
    opcode uint16
    data [1024]byte
}

var pkt1 packet
...
n, raddr, err := conn.ReadFromUDP(pkt1)  // error here
Run Code Online (Sandbox Code Playgroud)

此外,我想执行类似C的memcpy(),这将允许我直接将接收到的网络字节流映射到结构.

例如,以上收到的pkt1

type file_info struct {
    file_size uint32       // 4 bytes
    file_name [1020]byte
}

var file file_info
if (pkt1.opcode == WRITE) {
    memcpy(&file, pkt1.data, 1024)
}
Run Code Online (Sandbox Code Playgroud)

Ain*_*r-G 15

unsafe.Pointer是的,嗯,不安全,你实际上并不需要它.使用encoding/binary包代替:

// Create a struct and write it.
t := T{A: 0xEEFFEEFF, B: 3.14}
buf := &bytes.Buffer{}
err := binary.Write(buf, binary.BigEndian, t)
if err != nil {
    panic(err)
}
fmt.Println(buf.Bytes())

// Read into an empty struct.
t = T{}
err = binary.Read(buf, binary.BigEndian, &t)
if err != nil {
    panic(err)
}
fmt.Printf("%x %f", t.A, t.B)
Run Code Online (Sandbox Code Playgroud)

操场

正如您所看到的,它可以非常巧妙地处理大小和字节序.


小智 5

我遇到了同样的问题,我通过使用“encoding/binary”包解决了它。这是一个例子:

package main

import (
  "bytes"
  "fmt"
  "encoding/binary"
)

func main() {
  p := fmt.Println
  b := []byte{43, 1, 0}

  myStruct := MyStruct{}
  err := binary.Read(bytes.NewBuffer(b[:]), binary.BigEndian, &myStruct)

  if err != nil {
    panic(err)
  }

  p(myStruct)
}

type MyStruct struct {
  Num uint8
  Num2 uint16
}
Run Code Online (Sandbox Code Playgroud)

这是运行示例: https: //play.golang.org/p/Q3LjaAWDMh


One*_*One 1

你必须使用 unsafe,uint在 64 位系统上也是 8 个字节,如果你想要 4 个字节,你必须使用 uint32。

它很丑陋、不安全,而且你必须自己处理字节序。

type packet struct {
    opcode uint16
    data   [1022]byte
}

type file_info struct {
    file_size uint32     // 4 bytes
    file_name [1018]byte //this struct has to fit in packet.data
}

func makeData() []byte {
    fi := file_info{file_size: 1 << 20}
    copy(fi.file_name[:], []byte("test.x64"))
    p := packet{
        opcode: 1,
        data:   *(*[1022]byte)(unsafe.Pointer(&fi)),
    }
    mem := *(*[1022]byte)(unsafe.Pointer(&p))
    return mem[:]
}

func main() {
    data := makeData()
    fmt.Println(data)
    p := (*packet)(unsafe.Pointer(&data[0]))
    if p.opcode == 1 {
        fi := (*file_info)(unsafe.Pointer(&p.data[0]))
        fmt.Println(fi.file_size, string(fi.file_name[:8]))
    }
}
Run Code Online (Sandbox Code Playgroud)

play