乐趣区

关于golang:unsafe-非类型安全类型

unsafe 库彷徨在“类型平安”边缘,因为它们绕过了 Golang 的内存平安准则,个别被认为应用该库是不平安的。然而,在许多状况下,unsafe 库的作用又是不可代替的,灵便地应用它们能够实现对内存的间接读写操作。在 reflect 库、syscall 库以及其余许多须要操作内存的开源我的项目中都有对它的援用。

unsafe 库源码极少,只有两个类型的定义和三个办法的申明。

Pointer 类型

这个类型比拟重要,它是实现定位欲读写的内存的根底。官网文档对该类型有四个重要形容:
(1)任何类型的指针都能够被转化为 Pointer
(2)Pointer 能够被转化为任何类型的指针
(3)uintptr 能够被转化为 Pointer
(4)Pointer 能够被转化为 uintptr
举例来说,该类型能够这样应用:

func main() {
     i := 100
     fmt.Println(i) // 100
     p := (*int)unsafe.Pointer(&i)
     fmt.Println(*p) // 100
     *p = 0
     fmt.Println(i) // 0
     fmt.Println(*p) // 0
}

Sizeof 函数
该函数的定义如下:

func Offsetof(v ArbitraryType) uintptr

该函数返回由 v 所批示的某构造体中的字段在该构造体中的地位偏移字节数,留神,v 的表达方式必须是“struct.filed”模式。
举例说明,在 64 为零碎中运行以下代码:

type Datas struct{
    c0 byte
    c1 int
    c2 string
    c3 int
}
func main(){
    var d Datas
    fmt.Println(unsafe.Offset(d.c0)) // 0
    fmt.Println(unsafe.Offset(d.c1)) // 8
    fmt.Println(unsafe.Offset(d.c2)) // 16
    fmt.Println(unsafe.Offset(d.c3)) // 32
}

如果晓得的构造体的起始地址和字段的偏移值,就能够间接读写内存:

d.c3 = 13
p := unsafe.Pointer(&d)
offset := unsafe.Offsetof(d.c3)
q := (*int)(unsafe.Pointer(uintptr(p) + offset))
fmt.Println(*q) // 13
*p = 1013
fmt.Println(d.c3) // 1013
退出移动版