golang的unsafe包

unsafe包主要用于golang编译。其余地方不推荐使用。html

结构体的成员在内存中的分配是一段连续的内存,结构体中第一个成员的地址就是这个结构体的地址,也能够认为是相对于这个结构体偏移了0。相同的,这个结构体中的任一成员均可以相对于这个结构体的偏移来计算出它在内存中的绝对地址golang

在golang(1.10.3)中,unsafe包中有3个方法(参数不能为函数)web

  • unsafe.Sizeof() 获取字节数
  • unsafe.Offsetof() 获取偏移量
  • unsafe.Alignof() 获取对齐值

一个类型svg

  • unsafe.Pointer 获取任意类型地址的指针

另外,须要了解一个底层数据类型uintptr:函数

uintptr是golang的内置类型,是能存储指针的整型。uintptr值能够进行算术运算。经常使用于搭配unsafe.Pointer()来计算偏移量。ui

重点:spa

  • 任何类型的指针值均可以转换为unsafe.Pointer。
  • unsafe.Pointer能够转换为任何类型的指针值。
  • uintptr能够转换为unsafe.Pointer。
  • unsafe.Pointer能够转换为uintptr。
func TestUnsafe(t *testing.T) {
	type Num struct {
		i string
		j int64
		m bool
	}
	n := Num{"ABC", 123, true}
	nPointer := unsafe.Pointer(&n)

	fmt.Println("i的偏移量:", unsafe.Offsetof(n.i))
	fmt.Println("i占几个字节:", unsafe.Sizeof(n.i))
	fmt.Println("j的偏移量:", unsafe.Offsetof(n.j))
	fmt.Println("j占几个字节:", unsafe.Sizeof(n.j))
	fmt.Println("m的偏移量:", unsafe.Offsetof(n.m))
	fmt.Println("m占几个字节:", unsafe.Sizeof(n.m))

	niPointer := (*string)(unsafe.Pointer(uintptr(nPointer) + unsafe.Offsetof(n.i)))
	*niPointer = "QWE"
	njPointer := (*int64)(unsafe.Pointer(uintptr(nPointer) + unsafe.Offsetof(n.j)))
	*njPointer = 456
	nmPointer := (*bool)(unsafe.Pointer(uintptr(nPointer) + unsafe.Offsetof(n.m)))
	*nmPointer = false

	fmt.Println(n.i)
	fmt.Println(n.j)
	fmt.Println(n.m)
}

输出结果指针

i的偏移量: 0
i占几个字节: 16
j的偏移量: 16
j占几个字节: 8
m的偏移量: 24
m占几个字节: 1
QWE
456
false

还有不少地方不是很懂,未完待续。。。code

推荐文章
http://www.flysnow.org/2017/07/02/go-in-action-unsafe-memory-layout.htmlxml