Pointers 在Go中使用不安全的指针造成恐慌

Pointers 在Go中使用不安全的指针造成恐慌,pointers,go,slice,unsafe,Pointers,Go,Slice,Unsafe,代码是: package main import ( "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.Printl

代码是:

package main

import (
    "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]

为什么?

因为
buf
是一个片(不是数组),片只是描述符

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

输出(在上尝试):

如您所见,您设置的数据显示在第二个输出中(
10 0 0 0
int
10
的4个字节,
100 0 0 0
int
100
的4个字节)

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

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

buf := [50]byte{}
t := (*Point)(unsafe.Pointer(&buf))

通过这个更改,输出将是相同的。

我认为“make([]字节,50)”和“[50]字节{}”以前是相同的。非常感谢。@xiaobaowei
make([]字节,50)
是一个创建切片的程序,
[50]字节{}
是一个创建数组类型值的程序。
[50]字节
。不要使用包不安全。@Volker在性能相关的应用程序中有很多不安全的用法,尽管它被称为“不安全”,如果你用对了,它绝对没什么问题。我会说“不要用不安全的软件包在内存中随意翻找,期待任何好的东西”。我计算了将指针转换为片而不了解片在内存中如何表示为“随机戳内存”的不安全结果。
[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]
buf := [50]byte{}
t := (*Point)(unsafe.Pointer(&buf))