981377660LMT / ts

ts学习
6 stars 1 forks source link

golang指针转换 #541

Open 981377660LMT opened 4 months ago

981377660LMT commented 4 months ago

Go 指针、uintptr、unsafe.Pointer之间如何转换

unsafe.Pointer作为桥梁实现相互转换 普通指针 <=> unsafe.Pointer <=> uintptr

981377660LMT commented 4 months ago

可以看到 unsafe.Pointer 其实就是一个 *int,一个通用型的指针。

我们看下关于 unsafe.Pointer 的4个规则。

任何指针 都可以转换为 unsafe.Pointer unsafe.Pointer 可以转换为 任何指针 uintptr 可以转换为 unsafe.Pointer unsafe.Pointer 可以转换为 uintptr

981377660LMT commented 4 months ago

https://whiteccinn.github.io/2021/01/14/Golang/unsafe-Pointer/

981377660LMT commented 4 months ago

unsafe.Pointer在unsafe包中还有以下几个函数在我们计算可能会用到 ==unsafe包的几个函数==

//返回一个变量占用的内存字节数
func Sizeof(x ArbitraryType) uintptr

//返回结构体某个字段的地址相对于此结构体起始地址的偏移量
func Offsetof(x ArbitraryType) uintptr

//返回对齐系数
func Alignof(x ArbitraryType) uintptr
981377660LMT commented 4 months ago

// 如果是结构体的话,我们可以用到unsafe.Offsetof函数来计算 type People struct { age int32 height int64 } var p = new(People) height := unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Offsetof(p.height)) ((int)(height)) = 100 //将height的值改为100 //uintptr(unsafe.Pointer(p)) 获取了 w 的指针起始值 //unsafe.Offsetof(w.p) 获取 b 变量的偏移量


- uintptr和unsafe.Pointer的转换
```go
var p = &People
height := unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Offsetof(p.height))
*((*int)(height)) = 100 //将height的值改为100
981377660LMT commented 4 months ago

https://whiteccinn.github.io/2021/01/14/Golang/unsafe-Pointer/

981377660LMT commented 4 months ago

https://cloud.tencent.com/developer/article/2358351

981377660LMT commented 4 months ago

四、unsafe.Pointer强制转换 介绍这个方式之前,需要了解下go的指针。在go语言中有3类指针: 普通指针、uintptr、unsafe.Pointer。

普通指针 (T): 存储类型T的对象的地址,可以使用&(取地址)(根据地址取值),但不可计算 uintptr:一个无符号的整型,可以保存一个指针地址,可以进行计算。uintptr无法持有对象,GC不把uintptr当指针,所以uintptr类型的目标会被回收 unsafe.Ponter: 可以指向任意类型的指针,不能进行计算,不能读取内存存储的值 我们知道,指针的本质是一个uint类型,存储对象的地址(地址其实也是一个数字),在C语言中指针可以任意的计算、指向,因而存在比较大的风险。go语言为了避免指针被滥用、误用的风险,对指针做了限制(如类型校验、不可计算、不可跨类型转换等)。但同时也留了一个口子,允许指针进行跨类型转换,这便是unsafe.Pointer(从unsafe可以看出这个指针不安全的,使用不当容易出事)。

三类指针的特性如下:

普通指针(T)不可计算、不可转换 unsafe.Pointer可以和任意类型指针转换(T, uintptr, unsafe.Pointer) uintptr可以计算 因而借助unsave.Pointer、uintptr,我们可以实现对普通指针进行计算和跨类型转换。这第四种类型转换便是借助unsafe.Pointer可任意转换的能力来实现。

跨类型类型转换: newPtr := (newT)(unsave.Pointer(ptr)) 先转为unsafe.Pointer,再转为目标类型指针 ptr -> unsafe.Pointer -> newT 指针计算: 先转为unsafe.Pointer,再转为uintptr,进行指针计算,再转为unsafe.Pointer,最后转为目标普通指针 ptr -> unsafe.Pointer -> uintptr -> 指针计算 -> unsafe.Pointer -> ptr