在C ++中,您可以从FILE描述符中读取数据,然后只需重新解释_cast到结构中即可解释数据。
在Go中有等效的方法吗?
作为一个非常人为的示例,请考虑以下示例,其中“ ProcessBytes
”只是一个回调,其中给您提供了一个字节数组,这些字节数组在从文件中读取时会连续追加到后面。
struct PayloadHeader {
uint32_t TotalPayloadLength;
uint8_t PayloadType;
};
struct TextMessage {
PayloadHeader Header;
uint32_t SenderId;
uint32_t RecieverId;
char Text[64]; // null padded
};
void ProcessBytes(const uint8_t* data, size_t dataLength) {
if(dataLength < sizeof(PayloadHeader))
return;
const PayloadHeader* header = reinterpret_cast<const PayloadHeader*>(data);
if(header.PayloadType == TEXT_MESSAGE) {
if(header.TotalLength != sizeof(TextMessage))
return;
const TextMessage* text = reinterpret_cast<const TextMessage*>(data);
// Do something with the text message~
// Adjust the *data* to 'erase' the bytes after we are done processing it
// as a TextMessage
}
}
答案 0 :(得分:2)
目前,答案是unsafe
,但它们并没有说明为什么不应该使用unsafe
以及应该做什么。因此,让我尝试一下。
在OP中发布的C ++代码中,您似乎正在编写一种二进制格式,该二进制格式通过简单的强制转换读取数据。简单但有效。我能看到的唯一明显的问题是,它不允许Little Endian和Big Endian之间实现互操作性,但这是另一回事。
在Go中进行二进制编码的方法是使用方便的软件包encoding/binary
,该软件包能够将二进制数据直接解码为固定大小的结构(即,没有字符串或分片,它们是可变的) -length,因此长度需要任意编码)。
这是我在Go中实现您的示例的方式:
package main
import (
"bytes"
"encoding/binary"
"fmt"
)
const textMessage = 11
func main() {
// Set up our data - this is an example of the data I
// imagine you want to decode.
r := bytes.NewReader([]byte{
// Header
byte(textMessageLen + headerLen), 0, 0, 0,
11,
// Body
137, 0, 0, 0,
117, 0, 0, 0,
// Message content
'H', 'e', 'l', 'l', 'o', '!', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
})
// We first read the header to decide what to do next.
// Notice that we explicitly pass an argument that indicates to
// parse integers using little endian, making this code portable.
var h Header
err := binary.Read(r, binary.LittleEndian, &h)
if err != nil {
fmt.Println(err)
return
}
switch h.Type {
case textMessage:
// It's a text message - make sure the length is right.
if textMessageLen != (int(h.Length) - headerLen) {
fmt.Println("Invalid payload length")
return
}
// Decode the data
var t TextMessage
err = binary.Read(r, binary.LittleEndian, &t)
if err != nil {
fmt.Println(err)
return
}
// Print it out
fmt.Printf("Sender: %d; Receiver: %d\nMessage: %s\n",
t.Sender, t.Receiver, bytes.TrimRight(t.Text[:], "\x00"))
default:
fmt.Println("unknown payload type")
}
}
// If you need to find out what the encoded size of a struct is, don't use unsafe.Sizeof;
// use binary.Size instead.
var headerLen = binary.Size(Header{})
type Header struct {
Length uint32
Type uint8
}
var textMessageLen = binary.Size(TextMessage{})
type TextMessage struct {
Sender, Receiver uint32
Text [64]byte
}
所以,这里有几件事要注意:
binary.Read
和io.Reader
,这意味着当我们从中读取内容时,读取的数据将被丢弃,因此指针将自动前进。答案 1 :(得分:1)
可以,但是您不应该这样做,因为它不安全。 Golang未定义struct
的内存模型(据我所知),它可能会在golang版本之间改变。经常进行元帅/非元帅。
package main
import (
"fmt"
"unsafe"
)
type mys struct{
a int
}
func main() {
v := mys{0x1234abcd}
unsafeArrayP := (*[unsafe.Sizeof(v)]byte)(unsafe.Pointer(&v))
for i:=0;i<4;i++ {
fmt.Printf("%x,", unsafeArrayP[i])
}
v2 := 0x1234abcd
v3 := *((*mys)(unsafe.Pointer(&v2)))
fmt.Println(v == v3)
}
打印cd,ab,34,12,true