我是一个刚接触Go的C++背景的新手,偶然发现了一些奇怪的问题。代码如下:
package main
import (
"fmt"
"unsafe"
)
func main() {
arr := []string { "one", "two", "three" }
address := unsafe.Pointer(&arr)
addPtr := (*[]string)(unsafe.Pointer(*(*uintptr)(address)))
fmt.Println((*addPtr)[0])
}
此代码失败,并显示:
运行时错误:growslice:len超出范围
例如,如果我将类型转换为:
addPtr := (*[0]string)(unsafe.Pointer(*(*uintptr)(address)))
上面的代码工作得很好。
我理解这是一个转换到数组指针和数组必须有恒定的大小,但如何转换它到一个切片的指针呢?
更令人困惑的是,可以像这样获取slice的地址并将其分配给指针:
func main() {
arr := []string { "one", "two", "three" }
var arrPtr *[]string = &arr
fmt.Println((*arrPtr)[0])
}
这一次,尽管指针的类型与我在第一个例子中强制转换的不安全指针的类型相同,但一切都将正常工作。有人能帮我弄明白到底发生了什么吗?
1条答案
按热度按时间nwo49xxi1#
一些背景:切片头包含指向后备数组的指针、长度和容量。
问题的第一部分中的代码将切片头转换为指向切片头的指针。
go vet
命令警告问题中的代码可能是对unsafe.Pointer的误用。通过删除额外的解引用操作进行修复,以便代码从指向切片头的指针转换为指向切片头的指针。
不需要转换为 *uintptr。简化为:
不需要不安全的恶作剧。简化为:
使用以下代码将切片的后台数组指针转换为数组指针。代码是脆弱的,因为它假定切片头的第一个字是指向后备数组的指针。
不需要前面代码段中的uintptr转换。简化为:
希望这能帮上忙。