记录最近遇到的一些问题
定义
1.普通指针:*类型代表普通指针,用户传递对象的地址,但是不能进行指针的运算。
2.unsafe.Pointer:通用的指针类型,可以转换成任意的指针类型。不能进行指针的运算,也不能读取存储的值。如果要读取内存存储的值,需要转化为普通指针,再取值。
3.uintptr:可用于指针运算。并不是指针,可以将unsafe.Pointer指针转化为uintptr类型(是和当前指针相同的一个数字值),然后进行指针运算。
unsafe.Pointer
首先见官方文档给出的四个描述:
1.任何类型的指针都可以被转化为Pointer
2.Pointer可以被转化为任何类型的指针
3.uintptr可以被转化为Pointer
4.Pointer可以被转化为uintptr
普通的指针类型会写出T,表示是一个指向T类型变量的指针。而Pointer是一种特别定义的指针类型,它可以包含任意类型变量的地址。同时这也意味着我们无法通过”*p”的格式来获取指针指向的值,因为不知道具体的类型。Pointer指针是可比较的
关于官方文档中1、2两点,值得注意的是,普通的指针类型通过转向Pointer后再次转回指针类型,两次指针类型不需要相同
1 | func main() { |
1 | func main() { |
uintptr
uintptr是golang内置的一种存储指针的无符号整型类型。个人理解,它代表当前指针所指向的内存地址,以便于进行某种指针类型的运算。按照如上官方文档给出的描述,虽然uintptr可以转成Pointer,但由于并不是所有内存地址都是有效的,所以并不安全
下面是一个典型的uintptr使用案例:
1 | package main |
这里引出另外一个问题:不要试图设一个uintptr的临时变量!因为当垃圾回收器进行移动GC时,所有的保存某变量旧地址的指针必须同时被更新为变量移动后的新地址。而uintptr类型的临时变量只是一个数字,并不持有对象。垃圾回收器无法识别这是个指向变量t的指针。当变量t被移动后,临时变量的值就已经不是变量t的地址了。再使用临时变量就会出现不可预测的错误。