Pointer 指针 #
Go 中指针分为两种:
- 类型安全指针(如 *int, *string)
- 非类型安全指针(unsafe.Pointer)
关于 uintptr
:是一个无符号的整型,Go 的基本类型之一。主要用在为非类型安全指针(unsafe.Pointer)实现数值计算。
类型安全指针 #
Go (类型安全)指针的限制:
- Go 指针不能支持算术运算(如
p++
) - 一个指针类型的值不能被随意转换为另一个指针类型
- 一个指针值不能和其它任一指针类型的值进行比较(需要满足以下任意一个条件):
- 指针类型相同。
- 一个指针可以被隐式转换为另一个指针的类型。
- 其中一个且只有一个指针为
nil
。
- 一个指针值不能被赋值给其它任意类型的指针值
如果需要打破以上规则,则需要使用 unsafe.Pointer
。
非类型安全指针 unsafe.Pointer
#
只有以下六种使用 unsafe.Pointer
的方式是“合法”的:
- 将
*T1
转换为unsafe.Pointer
转换为*T2
(将值从类型T1
转换成T2
)。func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
- 将
unsafe.Pointer
转换为uintptr
(但不能再把它转回unsafe.Pointer
) - 将
unsafe.Pointer
转换为uintptr
,执行数学运算后再转回unsafe.Pointer
。(转换前后的指针必须指向同一个分配的内存块)(转换和运算必须在同一语句中,不能将其分开【可能会被 GC】)// equivalent to f := unsafe.Pointer(&s.f) f := unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f))
- 将
unsafe.Pointer
转换成uintptr
并传给syscall.Syscall
调用。【编译器赋予syscall.Syscall
的特权】 - 将
reflect.Value.Pointer
或reflect.Value.UnsafeAddr
的返回值从uintptr
转换成unsafe.Pointer
(也必须写在同一语句中,否则相应内存被 GC 的风险)。
p := (*int)(unsafe.Pointer(reflect.ValueOf(new(int)).Pointer()))
- 将
reflect.SliceHeader
或reflect.StringHeader
的Data
字段(uintptr
类型)转换为unsafe.Pointer
或反转。