go普通指针、unsafe.Poniter、unintptr之间的联系

go普通指针、unsafe.Poniter、unintptr之间的联系

GO指针

. 普通指针 *type 普通指针,用于传递对象地址,不能进行指针运算
. unsafe.Poniter 通用型指针,用于不同类型指针的转换,不能进行指针运算,不能读取内存存储的值
. unintptr 可进行指针运算,由于其无法持有对象,GC不把unintptr当作指针,unintptr常被回收

unsafe.Pointer 是桥梁,可以让任意类型的指针实现相互转换,也可以将任意类型的指针转换为 uintptr 进行指针运算。
只有uintptr类型才可以进行运算,只要将普通指针类型转换成uintptr类型,做完加减法后,再转换成普通指针,通过*操作,取值,修改值,随意。
总结:unsafe.Pointer 可以让你的变量在不同的普通指针类型转来转去,也就是表示为任意可寻址的指针类型。而 uintptr 常用于与 unsafe.Pointer 打配合,用于做指针运算

unsafe.Pointer

  • 用于各种指针相互转换的桥梁,它可以包含任意类型变量的地址
  • 当然,我们不可以直接通过*p来获取unsafe.Pointer指针指向的真实变量的值,因为我们并不知道变量的具体类型。
  • 和普通指针一样,unsafe.Pointer指针也是可以比较的,并且支持和nil常量比较判断是否为空指针。

uintptr

  • uintptr是一个整数类型。即使uintptr变量仍然有效,由uintptr变量表示的地址处的数据也可能被GC回收,这个需要注意!

unsafe包

-unsafe包只有两个类型,三个函数

type ArbitraryType int
type Pointer *ArbitraryType
func Sizeof(x ArbitraryType) uintptr //返回其占用的字节数
func Offsetof(x ArbitraryType) uintptr  //返回结构体中元素所在的内存的偏移量
func Alignof(x ArbitraryType) uintptr  //返回变量对齐字节数量

-三个函数的参数均是ArbitraryType类型,就是接受任何类型的变量。

运用

unsafe.pointer用于普通指针类型转换

v1 := int(12)
p = (*uint)(unsafe.Pointer(&v2))

unsafe.pointer用于访问操作结构体的私有变量

type V struct {
    i int32
    j int64
}

func main() {
    var v *V = new(V)
    var i *int32 = (*int32)(unsafe.Pointer(v))
    *i = int32(98)
    var j *int64 = (*int64)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + uintptr(unsafe.Sizeof(int32(0)))))
    *j = int64(763)
    v.PutI()
    v.PutJ()
} 
func main() {
    var b []byte = []byte{'a', 'b', 'c'}
    var c *byte = &b[0]
    fmt.Println(*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + uintptr(1))))
}

//错误写法,不要试图引入一个uintptr类型的临时变量,因为它可能会破坏代码的安全性,随时可能被GC回收影响
tmp := uintptr(unsafe.Pointer(c)) + uintptr(1)
pb := (*byte)(unsafe.Pointer(tmp))
*pb = 'd'

原文地址:https://www.cnblogs.com/fanzou/p/13100137.html