pointer 指针

Pointer 指针 #

Go 中指针分为两种:

  • 类型安全指针(如 *int, *string)
  • 非类型安全指针(unsafe.Pointer)

关于 uintptr :是一个无符号的整型,Go 的基本类型之一。主要用在为非类型安全指针(unsafe.Pointer)实现数值计算。

类型安全指针 #

Go (类型安全)指针的限制:

  • Go 指针不能支持算术运算(如 p++)
  • 一个指针类型的值不能被随意转换为另一个指针类型
  • 一个指针值不能和其它任一指针类型的值进行比较(需要满足以下任意一个条件):
    1. 指针类型相同。
    2. 一个指针可以被隐式转换为另一个指针的类型。
    3. 其中一个且只有一个指针为 nil
  • 一个指针值不能被赋值给其它任意类型的指针值

如果需要打破以上规则,则需要使用 unsafe.Pointer

非类型安全指针 unsafe.Pointer #

只有以下六种使用 unsafe.Pointer 的方式是“合法”的:

  1. *T1 转换为 unsafe.Pointer 转换为 *T2 (将值从类型 T1 转换成 T2)。
    func Float64bits(f float64) uint64 {
        return *(*uint64)(unsafe.Pointer(&f))
    }
    
  2. unsafe.Pointer 转换为 uintptr (但不能再把它转回 unsafe.Pointer
  3. unsafe.Pointer 转换为 uintptr ,执行数学运算后再转回 unsafe.Pointer。(转换前后的指针必须指向同一个分配的内存块)(转换和运算必须在同一语句中,不能将其分开【可能会被 GC】)
     // equivalent to f := unsafe.Pointer(&s.f)
     f := unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f))
    
  4. unsafe.Pointer 转换成 uintptr 并传给 syscall.Syscall 调用。【编译器赋予 syscall.Syscall 的特权】
  5. reflect.Value.Pointerreflect.Value.UnsafeAddr 的返回值从 uintptr 转换成 unsafe.Pointer (也必须写在同一语句中,否则相应内存被 GC 的风险)。
p := (*int)(unsafe.Pointer(reflect.ValueOf(new(int)).Pointer()))
  1. reflect.SliceHeaderreflect.StringHeaderData 字段(uintptr 类型)转换为 unsafe.Pointer 或反转。

References #