加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

数组 – 如何在golang中的数组unsafe.Pointer中创建数组或切片?

发布时间:2020-12-16 09:26:56 所属栏目:大数据 来源:网络整理
导读:一个指向数组的指针,让我们说: p := uintptr(unsafe.Pointer(array))size := 5 我无法访问变量数组,上面的代码用于使其更清晰. 另外,我知道数组的大小,但是大小不是常量,它会根据运行时间而变化. 现在,我想用已知的指针,大小以及数据类型初始化切片或数组.
一个指向数组的指针,让我们说:

p := uintptr(unsafe.Pointer(&array))
size := 5

我无法访问变量数组,上面的代码用于使其更清晰.

另外,我知道数组的大小,但是大小不是常量,它会根据运行时间而变化.

现在,我想用已知的指针,大小以及数据类型初始化切片或数组.

我想出了以下代码:

data := make([]byte,size)
stepSize := unsafe.Sizeof(data[0])
for i := 0; i < size; i++ {
    data[i] = *(*byte)(unsafe.Pointer(p))
    p += stepSize
}
fmt.println(data)

但是这个方法会进行内存复制,这可能是效率低下的,无论如何都没有复制?

附:我也尝试了以下两种方法,

// method 1
data := *(*[]byte)(unsafe.Pointer(p))
// method 2
data := *(*[size]byte)(unsafe.Pointer(p))

但它会在运行时失败,我现在知道它的原因.

解决方法

前言:

您应该知道:如果您将指针作为uintptr类型的值,则不会阻止原始数组进行垃圾回收(uintptr值不计入引用).所以在使用这样的值时要小心,不能保证它会指向有效的值/内存区域.

从包unsafe.Pointer引用:

A uintptr is an integer,not a reference. Converting a Pointer to a uintptr creates an integer value with no pointer semantics. Even if a uintptr holds the address of some object,the garbage collector will not update that uintptr’s value if the object moves,nor will that uintptr keep the object from being reclaimed.

一般建议:尽可能远离包装不安全.留在Go的类型安全.

声明切片类型的变量,并使用不安全的转换来获取其reflect.SliceHeader描述符.

然后,您可以使用指针作为SliceHeader.Data值修改其字段,并将大小修改为SliceHeader.Len和SliceHeader.Cap.

完成此操作后,slice变量将指向与初始指针相同的数组.

arr := [10]byte{0,1,2,3,4,5,6,7,8,9}

size := len(arr)
p := uintptr(unsafe.Pointer(&arr))

var data []byte

sh := (*reflect.SliceHeader)(unsafe.Pointer(&data))
sh.Data = p
sh.Len = size
sh.Cap = size

fmt.Println(data)

runtime.KeepAlive(arr)

输出(在Go Playground上试试):

[0 1 2 3 4 5 6 7 8 9]

请注意,我使用了runtime.KeepAlive().这是因为在获取arr的地址并获取其长度之后,我们不再引用arr(p是uintptr不算作参考),并且积极的GC可能正确地擦除arr在我们到达打印数据之前(指向arr).将runtime.KeepAlive()放到main()的末尾将确保不会对arr进行垃圾回收
?在这个电话之前.有关详细信息,请参阅In Go,when will a variable become unreachable?如果指针的供应商确保不会对其进行垃圾回收,则无需在代码中调用runtime.KeepAlive().

或者,您可以使用composite literal创建一个reflect.SliceHeader,并使用不安全的转换从中获取切片,如下所示:

sh := &reflect.SliceHeader{
    Data: p,Len:  size,Cap:  size,}

data := *(*[]byte)(unsafe.Pointer(sh))

fmt.Println(data)

runtime.KeepAlive(arr)

输出将是相同的.在Go Playground尝试这个.

这个可能性/用例记录在unsafe.Pointer,注意事项和警告:

(6) Conversion of a reflect.SliceHeader or reflect.StringHeader Data field to or from Pointer.

As in the previous case,the reflect data structures SliceHeader and StringHeader declare the field Data as a uintptr to keep callers from changing the result to an arbitrary type without first importing “unsafe”. However,this means that SliceHeader and StringHeader are only valid when interpreting the content of an actual slice or string value.

06003

In this usage hdr.Data is really an alternate way to refer to the underlying pointer in the slice header,not a uintptr variable itself.

In general,reflect.SliceHeader and reflect.StringHeader should be used only as *reflect.SliceHeader and *reflect.StringHeader pointing at actual slices or strings,never as plain structs. A program should not declare or allocate variables of these struct types.

06004

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读