Struct 结构和字节数组之间的Go转换

Struct 结构和字节数组之间的Go转换,struct,casting,go,memcpy,Struct,Casting,Go,Memcpy,我正在用Go编写一个客户机-服务器应用程序。我想在围棋中进行C型铸造 例如围棋 type packet struct { opcode uint16 data [1024]byte } var pkt1 packet ... n, raddr, err := conn.ReadFromUDP(pkt1) // error here 我还想执行类似于C的memcpy(),这将允许我直接将接收到的网络字节流映射到一个struct e、 g.具有上述收到的pkt1 type fi

我正在用Go编写一个客户机-服务器应用程序。我想在围棋中进行C型铸造

例如围棋

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

var pkt1 packet
...
n, raddr, err := conn.ReadFromUDP(pkt1)  // error here
我还想执行类似于C的memcpy(),这将允许我直接将接收到的网络字节流映射到一个struct

e、 g.具有上述收到的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)
}

您必须使用不安全的,而且在64位系统上,uint是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]))
    }
}
类型数据包结构{
操作码uint16
数据[1022]字节
}
类型文件\u信息结构{
文件大小uint32//4字节
文件名[1018]字节//此结构必须适合packet.data
}
func makeData()[]字节{

fi:=file_info{file_size:1
不安全。指针是不安全的,您实际上不需要它。请改用包:

// 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)


正如您所看到的,它处理大小和尾端非常整洁。

谢谢您的回答,我确信它们工作得很好。但在我的例子中,我更感兴趣的是解析作为网络数据包接收的[]字节缓冲区。我使用以下方法解析缓冲区

var data []byte // holds the network packet received
opcode := binary.BigEndian.Uint16(data) // this will get first 2 bytes to be interpreted as uint16 number
raw_data := data[2:len(data)] // this will copy rest of the raw data in to raw_data byte stream
从结构构造[]字节流时,可以使用以下方法

type packet struct {
    opcode uint16
    blk_no uint16
    data   string
}
pkt := packet{opcode: 2, blk_no: 1, data: "testing"}
var buf []byte = make([]byte, 50) // make sure the data string is less than 46 bytes
offset := 0
binary.BigEndian.PutUint16(buf[offset:], pkt.opcode)
offset = offset + 2
binary.BigEndian.PutUint16(buf[offset:], pkt.blk_no)
offset = offset + 2
bytes_copied := copy(buf[offset:], pkt.data)

我希望这能提供关于如何将[]字节流转换为struct,并将struct转换回[]字节流的一般思路。

我遇到了同样的问题,我使用“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
}

下面是一个运行示例:

我建议您先在go中编写它。在go中您不会做类似的事情。除此之外,go没有强制转换。
uint
也不是4字节。
Conn.Read
需要
[]字节
,它实际上是一个智能的、大小合适的指针,指向一个支持数组。您只需在go中编写它就会有一个更好的时间。您是否已经看过使用
编码/gob
包的内置二进制序列化?