func Encode(i interface{}) ([]byte, error) {
buffer := bytes.NewBuffer(make([]byte, 0, 1024))
// size := unsafe.Sizeof(i)
size := reflect.TypeOf(i).Size()
fmt.Println(size)
ptr := unsafe.Pointer(&i)
startAddr := uintptr(ptr)
endAddr := startAddr + size
for i := startAddr; i < endAddr; i++ {
bytePtr := unsafe.Pointer(i)
b := *(*byte)(bytePtr)
buffer.WriteByte(b)
}
return buffer.Bytes(), nil
}
func TestEncode(t *testing.T) {
test := Test{10, "hello world"}
b, _ := Encode(test)
ptr := unsafe.Pointer(&b)
newTest := *(*Test)(ptr)
fmt.Println(newTest.X)
}
我正在学习如何使用 golang unsafe 并编写此函数来对任何对象进行编码。我遇到两个问题,首先,剂量 unsafe.Sizeof(obj) 总是返回 obj 的指针大小?为什么它不同于 reflect.TypeOf(obj).Size()?其次,我想通过unsafe.Pointer()在TestEncode函数中遍历obj的底层字节并转换回obj,但是对象的值都损坏了,为什么?
最佳答案
首先,unsafe.Sizeof
返回需要存储类型的字节。这有点棘手,但它并不意味着需要存储数据的字节。
比如一个slice,众所周知,在32bit的机器上存储了3个4字节的int。一个 uintptr 用于底层数组的内存地址,两个 int32
用于 len
和 cap
。所以无论一个 slice 有多长或它是什么类型,一个 slice 在 32 位机器上总是占用 12 个字节。一个字符串可能使用 8 个字节:1 个 uintptr
用于地址,1 个 int32
用于 len
。
至于reflect.TypeOf().Size
的区别,是关于接口(interface)的。 reflect.TypeOf
查看接口(interface)并获取具体类型,并报告具体类型所需的字节数,而 unsafe.Sizeof
仅返回 8 接口(interface)类型:2 uintptr
用于指向数据的指针和指向方法列表的指针。
第二部分现在已经很清楚了。其一,unsafe.Pointer
获取接口(interface)的地址,而不是具体类型。第二,在 TestEncode
中,unsafe.Pointer
正在获取 12 字节 slice “ header ”的地址。可能还有其他错误,但对于上述两个错误,发现它们毫无意义。
注意:我避免谈论 uintptr
和 int32
的命令,不仅因为我不知道,而且因为它们没有文档记录、不安全和实现视情况而定。
注意 2:结论:不要尝试转储 Go 数据的内存。
注意 3:我将所有内容都更改为 32 位,因为 playground 正在使用它,因此更容易检查。
关于go - 通过 golang 将对象编码为字节不安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48654563/