Golang 中的 unsafe.Pointer 和 uintptr
创始人
2024-06-03 11:59:00
0

golang的指针类型和c/c++的指针类型基本一样,但是多了几个限制:

1,int,int32等不同的指针类型不能相互转化.
2,指针类型不支持c/c++这样的指针运算。

1、uintptr

// uintptr is an integer type that is large enough to hold the bit pattern of
// any pointer.
type uintptr uintptr
  • uintptr 是一个整数类型(这个非常重要),注意,他不是个指针;
  • 但足够保存任何一种指针类型。

uintptr 是一个地址数值,它不是指针,与地址上的对象没有引用关系,垃圾回收器不会由于有一个uintptr类型的值指向某对象而不回收该对象。
unsafe.Pointer是一个指针,相似于C的void *,它与地址上的对象存在引用关系,垃圾回收器会由于有一个unsafe.Pointer类型的值指向某对象而不回收该对象。

  • 任何指针均可以转为unsafe.Pointer
  • unsafe.Pointer能够转为任何指针
  • uintptr能够转换为unsafe.Pointer
  • unsafe.Pointer能够转换为uintptr
  • 指针不能直接转换为uintptr

理论上说指针不过是一个数值,即一个uint,但实际上在go中unsafe.Pointer是不能经过强制类型转换为一个uint的,只能将unsafe.Pointer强制类型转换为一个uintptr

2、unsafe 包支持了这些方法来完成【类型】=> uintptr 的转换:

func Sizeof(x ArbitraryType) uintptr
func Offsetof(x ArbitraryType) uintptr
func Alignof(x ArbitraryType) uintptr

3、使用示例

https://juejin.cn/post/7127600972573966373

3.1 常规类型互转

func Float64bits(f float64) uint64 {return *(*uint64)(unsafe.Pointer(&f))
}

其实本质就是把 unsafe.Pointer 当成了一个媒介。用到了他可以从任意一个类型转换得来,也可以转为任意一个类型。

这样的用法有一定的前提:

  • 转化的目标类型(uint64) 的 size 一定不能比原类型 (float64)还大(二者size都是8个字节);
  • 前后两种类型有等价的 memory layout;

3.2 指针算数计算:Pointer => uintptr => Pointer

将一个指针转为 uintptr 将会得到它指向的内存地址,而我们又可以结合 SizeOf,AlignOf,Offsetof 来计算出来另一个 uintptr 进行计算。

这类场景最常见的是【获取结构体中的变量】或【数组中的元素】。

# 注意:变量到 uintptr 的转换以及计算必须在一个表达式中完成(需要保证原子性):
f := unsafe.Pointer(&s.f) 
f := unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f))e := unsafe.Pointer(&x[i])
e := unsafe.Pointer(uintptr(unsafe.Pointer(&x[0])) + i*unsafe.Sizeof(x[0]))

uintptr + offset 算地址,再跟 Pointer 转化其实是一个很强大的能力,我们再来看一个实际的例子:

package main
import ("fmt""unsafe"
)
func main() {length := 6arr := make([]int, length)for i := 0; i < length; i++ {arr[i] = i}fmt.Println(arr)// [0 1 2 3 4 5]// 取slice的第5个元素:通过计算第1个元素 + 4 个元素的size 得出end := unsafe.Pointer(uintptr(unsafe.Pointer(&arr[0])) + 4*unsafe.Sizeof(arr[0]))fmt.Println(*(*int)(end)) // 4fmt.Println(arr[4]) // 4}

unsafe.Pointer 不能进行算数计算,uintptr 其实是很好的一个补充。

3.3 reflect 包中从 uintptr => Ptr

正例:

p := (*int)(unsafe.Pointer(reflect.ValueOf(new(int)).Pointer()))

反例:

u := reflect.ValueOf(new(int)).Pointer()
p := (*int)(unsafe.Pointer(u))

3.4 sync.Pool

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...