Press "Enter" to skip to content

golang中的uintptr和unsafe.Pointer

uintptr是一个整数类型。
即使uintptr变量仍然有效,由uintptr变量表示的地址处的数据也可能被GC回收。


unsafe.Pointer是一个指针类型。
但是unsafe.Pointer值不能被取消引用。
如果unsafe.Pointer变量仍然有效,则由unsafe.Pointer变量表示的地址处的数据不会被GC回收。
unsafe.Pointer是一个通用的指针类型,就像* int等

	a := [4]int{0, 1, 2, 3}
	fmt.Printf("a[1]的地址为:%p, 类型为:%T\n", &a[1], &a[1]) // a[1]的地址为:0xc00012c008, 类型为:*int
	p1 := unsafe.Pointer(&a[1])
	fmt.Printf("unsafe.Pointer转换后的a[1]的地址为:%p, 类型为:%T\n", p1, p1) // unsafe.Pointer转换后的a[1]的地址为:0xc00012c008, 类型为:unsafe.Pointer
	fmt.Println(uintptr(p1))                                      //  824633827464
	fmt.Println(2 * unsafe.Sizeof(a[0]))                          // 16
	res := uintptr(p1) + 2*unsafe.Sizeof(a[0])
	fmt.Println(res) // 824633827480
	p3 := unsafe.Pointer(res)
	fmt.Println(p3) //0xc00001a098,在0xc00012c008的基础上加了16
        *(*int)(p3) = 6
        fmt.Println(a)   // [0, 1, 2, 6]
unsafe.Pointer()的作用理解就是把一个普通的指针转换为unsafe.Pointer类型,只有这个类型可以让指针的十六进制通过uintptr()进行转为十进制,然后可以通过这个uintptr类型变量进行运算,最后再让这个uintptr类型的变量通过unsafe.Pointer()转为十六进制指针
*(*int)(p3), 这句话可以得到运算后的地址的值,众所周知,数组元素的地址在内存中是连续的,间隔的值为所属数据类型的大小

2 * unsafe.Sizeof(a[0]) , unsafe.Sizeof(a[0]) 可得到a[0]为8个字节,再*2得16, 所以 p3 的地址现在就为a[3]的地址,运算使其往后移动了2个元素。
unsafe.Pointer类型无法像普通指针一样取值,如 *p3 = 6,所以使用*(*int)(p3)这种方式进行取值,最后修改为6,故最后a数组的结果为 [0, 1, 2, 6] 
发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注