uintptr和unsafe.Pointer的区别

学习播客:https://zhuanlan.zhihu.com/p/395234447

unsafe.Pointer只是单纯的通用指针类型,用于转换不同类型的指针
它不可以参与指针运算;
不能读取内存存储的值,必须转换到某一类型的普通指针。

uintptr用于指针运算,GC 不把 uintptr 当指针,即 uintptr 无法持有对象, uintptr 类型的目标会被回收;
unsafe.Pointer 可以和 普通指针 进行相互转换;
unsafe.Pointer 可以和 uintptr 进行相互转换。

实例

package main

import (
 "fmt"
 "unsafe"
)

type W struct {
 b int32
 c int64
}

func main() {
	var w *W = new(W)
	fmt.Println(w.b,w.c) // 0 0

	//通过指针运算给b赋值10
	b := unsafe.Pointer(unsafe.Offsetof(w.b) + uintptr(unsafe.Pointer(w)))
	*((*int)(b)) = 10
	fmt.Println(w.b,w.c) //10 0

	c := unsafe.Offsetof(w.b) + uintptr(unsafe.Pointer(w))
	fmt.Printf("type %T", c) // uintptr
}

注意:
unsafe.Offsetof(w.b) + uintptr(unsafe.Pointer(w)) 后的类型是 uintptr ,需要强转为 unsafe.Pointer

unsafe.pointer

从名字来看它是不安全的和指针相关,unsafer.pointer主要的功能就是不同类型指针间的转换。

不同类型之间不能直接转换

func main() {
   var a *int8
   var b *int16
   a = new(int8)
   b = new(int16)
   *b = 10
   *a = *b
   fmt.Println(a)
}

结果:
cannot use *b (type int16) as type int8 in assignment

go是强类型语言,这种即使都是int,这样转换也是不行的,于是出现了unsafe.pointer。
通过unsafe.pointer来转换

var a *int8
var b *int16
a = new(int8)
b = new(int16)
*b = 10
upb := unsafe.Pointer(b) // *int16 转 unsafe.Pointer
b_int8ptr := (*int8)(upb) // unsafe.Pointer 转 *int8
*a = *(b_int8ptr)
fmt.Println(*a) // 10
unsafer.pointer可以转换不同类型的指针。

unintptr

uintptr 实际上就是一个 uint ,用来表示地址

var a, b uintptr
a = 10
b = 10
fmt.Println(a + b)

同类型的具体地址不能直接相加

var a, b *int
a, b = new(int), new(int)
c:=a+b  //invalid operation: a + b (operator + not defined on pointer)

同类型的通用地址不能直接相加

var a, b *int
a, b = new(int), new(int)
c := unsafe.Pointer(a) + unsafe.Pointer(b) // invalid operation: unsafe.Pointer(a) + unsafe.Pointer(b) (operator + not defined on unsafe.Pointer)

结合uintptr来做地址之间的运算

var a, b *int
a, b = new(int), new(int)
c := uintptr(unsafe.Pointer(a)) + uintptr(unsafe.Pointer(b))
fmt.Println(c)

你可能感兴趣的:(go,golang,开发语言,后端)