从字节切片到结构的类型转换不安全

时间:2019-01-06 00:02:00

标签: go types unsafe-pointers

我试图理解为什么Go中的代码无法按我认为的方式工作。当我执行此测试时,它失败:

func TestConversion(t *testing.T) {
    type myType struct {
        a     uint8
        value uint64
    }
    myVar1 := myType{a: 1, value: 12345}

    var copyFrom []byte
    copyFromHeader := (*reflect.SliceHeader)(unsafe.Pointer(&copyFrom))
    copyFromHeader.Data = uintptr(unsafe.Pointer(&myVar1))
    copyFromHeader.Cap = 9
    copyFromHeader.Len = 9

    copyTo := make([]byte, len(copyFrom))

    for i := range copyFrom {
        copyTo[i] = copyFrom[i]
    }

    myVar2 := (*myType)(unsafe.Pointer(&copyFrom[0]))
    myVar3 := (*myType)(unsafe.Pointer(&copyTo[0]))

    if myVar2.value != myVar3.value {
        t.Fatalf("Expected myVar3.value to be %d, but it is %d", myVar2.value, myVar3.value)
    }
}

输出将是:

slab_test.go:67: Expected myVar3.value to be 12345, but it is 57

但是,如果我在复制数据之前将copyFromHeader.Data增加1,则一切正常。像这样:

copyFromHeader.Data = uintptr(unsafe.Pointer(&myVar1)) + 1

我不明白为什么它似乎将基础数据移位了一个字节。

1 个答案:

答案 0 :(得分:1)

avalue之间有7个填充字节。您仅在value中得到最低有效字节12345(57)。当您将copyFrom下移一个字节时,myVar2.valuemyVar3.value的值均为48(12345的第二个字节),因此测试通过。如果将9更改为16,它应该可以工作。

以这种方式复制结构是否有某些特殊原因?