为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中使用 unsafe.Pointer 的恐慌

在 Go 中使用 unsafe.Pointer 的恐慌

Go
慕村225694 2021-11-01 10:51:11
代码是:package mainimport (    "fmt"    "unsafe")type Point struct {    x int     y int }func main() {    buf := make([]byte, 50)     fmt.Println(buf)    t := (*Point)(unsafe.Pointer(&buf))    t.x = 10    t.y = 100     fmt.Println(buf)}运行它时,会发生运行时恐慌:panic: runtime error: invalid memory address or nil pointer dereference[signal 0xb code=0x1 addr=0xa pc=0x43dd4d]为什么?
查看完整描述

1 回答

?
函数式编程

TA贡献1807条经验 获得超9个赞

因为buf是切片(不是数组),切片只是描述符。


您很可能想写入分配字节的内存空间,因此不要使用切片描述符的地址,而是使用分配字节的地址,您可以通过获取第一个元素的地址来获得(切片描述底层数组的连续部分):


t := (*Point)(unsafe.Pointer(&buf[0]))

输出(在Go Playground上试试):


[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]

[10 0 0 0 100 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]

正如你可以看到,可以设置数据出现在第二输出(10 0 0 0是4个字节的int值10,100 0 0 0是4个字节的int值100)。


如果您使用切片描述符的地址,您会看到恐慌,因为描述符包含诸如第一个元素的地址、元素计数和容量之类的内容。因此,通过使用描述符的地址,您将修改这些地址,并且在尝试将其作为切片再次打印时,您写入的数据很可能位于无效指针中。您可以通过写入十六进制值来确认10这一点0xa,并且错误消息包含:addr=0xa


另一种选择是使用“真实”数组而不是切片,因为数组不是描述符:


buf := [50]byte{}

t := (*Point)(unsafe.Pointer(&buf))

有了这个改变,输出将是相同的。


查看完整回答
反对 回复 2021-11-01
  • 1 回答
  • 0 关注
  • 174 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信