学习播客:https://zhuanlan.zhihu.com/p/395234447
unsafe.Pointer只是单纯的通用指针类型,用于转换不同类型的指针
它不可以参与指针运算;
不能读取内存存储的值,必须转换到某一类型的普通指针。
uintptr用于指针运算,GC 不把 uintptr 当指针,即 uintptr 无法持有对象, uintptr 类型的目标会被回收;
unsafe.Pointer 可以和 普通指针 进行相互转换;
unsafe.Pointer 可以和 uintptr 进行相互转换。
package main
import (
"fmt"
"unsafe"
)
type W struct {
b int32
c int64
}
func main() {
var w *W = new(W)
fmt.Println(w.b,w.c) // 0 0
//通过指针运算给b赋值10
b := unsafe.Pointer(unsafe.Offsetof(w.b) + uintptr(unsafe.Pointer(w)))
*((*int)(b)) = 10
fmt.Println(w.b,w.c) //10 0
c := unsafe.Offsetof(w.b) + uintptr(unsafe.Pointer(w))
fmt.Printf("type %T", c) // uintptr
}
注意:
unsafe.Offsetof(w.b) + uintptr(unsafe.Pointer(w)) 后的类型是 uintptr ,需要强转为 unsafe.Pointer
从名字来看它是不安全的和指针相关,unsafer.pointer主要的功能就是不同类型指针间的转换。
不同类型之间不能直接转换
func main() {
var a *int8
var b *int16
a = new(int8)
b = new(int16)
*b = 10
*a = *b
fmt.Println(a)
}
结果:
cannot use *b (type int16) as type int8 in assignment
go是强类型语言,这种即使都是int,这样转换也是不行的,于是出现了unsafe.pointer。
通过unsafe.pointer来转换
var a *int8
var b *int16
a = new(int8)
b = new(int16)
*b = 10
upb := unsafe.Pointer(b) // *int16 转 unsafe.Pointer
b_int8ptr := (*int8)(upb) // unsafe.Pointer 转 *int8
*a = *(b_int8ptr)
fmt.Println(*a) // 10
unsafer.pointer可以转换不同类型的指针。
uintptr 实际上就是一个 uint ,用来表示地址
var a, b uintptr
a = 10
b = 10
fmt.Println(a + b)
同类型的具体地址不能直接相加
var a, b *int
a, b = new(int), new(int)
c:=a+b //invalid operation: a + b (operator + not defined on pointer)
同类型的通用地址不能直接相加
var a, b *int
a, b = new(int), new(int)
c := unsafe.Pointer(a) + unsafe.Pointer(b) // invalid operation: unsafe.Pointer(a) + unsafe.Pointer(b) (operator + not defined on unsafe.Pointer)
结合uintptr来做地址之间的运算
var a, b *int
a, b = new(int), new(int)
c := uintptr(unsafe.Pointer(a)) + uintptr(unsafe.Pointer(b))
fmt.Println(c)