代码之家  ›  专栏  ›  技术社区  ›  xiaobao wei

恐慌使用不安全。Go中的指针

  •  -1
  • xiaobao wei  · 技术社区  · 9 年前

    代码为:

    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]
    

    为什么?

    1 回复  |  直到 9 年前
        1
  •  5
  •   icza    8 年前

    因为 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 int 价值 10 , 100 0 0 0 整数 价值 100 ).

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

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

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

    随着这一变化,输出将保持不变。