unsafe包主要用于golang编译。其他地方不推荐使用。
结构体的成员在内存中的分配是一段连续的内存,结构体中第一个成员的地址就是这个结构体的地址,也可以认为是相对于这个结构体偏移了0。相同的,这个结构体中的任一成员都可以相对于这个结构体的偏移来计算出它在内存中的绝对地址
在golang(1.10.3)中,unsafe包中有3个方法(参数不能为函数)
- unsafe.Sizeof() 获取字节数
- unsafe.Offsetof() 获取偏移量
- unsafe.Alignof() 获取对齐值
一个类型
- unsafe.Pointer 获取任意类型地址的指针
另外,需要了解一个底层数据类型uintptr:
uintptr是golang的内置类型,是能存储指针的整型。uintptr值可以进行算术运算。常用于搭配unsafe.Pointer()来计算偏移量。
重点:
- 任何类型的指针值都可以转换为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
还有很多地方不是很懂,未完待续。。。
推荐文章
http://www.flysnow.org/2017/07/02/go-in-action-unsafe-memory-layout.html