go unsafe
1 一些方法
1.1 unsafe.Slice
Tip
Go 1.17 新增 unsafe.Slice
// 等价于 (*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]
func TestSlice(t *testing.T) {
st := struct {
a int8 // 内存对齐, 导致补一个字节
b int16 // 516 ==> 高位字节是 2, 低位字节是4 0x204
c int32
}{1, 516, 3}
// unsafe.Slice 把任何指针变成一个切片
// 切片元素类型是 转递的参数指针的类型 , 这里就是 int8
// 比如 如果你传递 &st 虽然地址与&st.a 一样, 但是结果就不一样了.
slice := unsafe.Slice(&st.a, 5)
println(len(slice), cap(slice))
// 1 ?(不确定的污染数据) 4 2
println(slice[0], slice[1], slice[2], slice[3])
}1.2 unsafe.SliceData
Tip
Go 1.20 新增 unsafe.SliceData
1.3 unsafe.Add
Tip
uintptr的+ 的操作的简便方式
type MyStruct struct {
age int16
height int16
}
func TestUnsafeAdd(t *testing.T) {
var ms MyStruct
ms.age = 32
ms.height = 182
ptr := unsafe.Pointer(&ms)
offset := unsafe.Offsetof(ms.height)
fmt.Println(offset)
newPtr := unsafe.Add(ptr, offset)
// 访问新的地址处的值
fmt.Println(*(*int16)(newPtr)) // 输出 182
}1.4 unsafe.String
func TestUnsafe(t *testing.T) {
slice := []byte{'h', 'e', 'l', 'l', 'o'}
// 参数1: 字符数组的地址, 参数2: 字符数组长度
// 是字符串的2个组成部分
s := unsafe.String(&slice[0], 3)
println(s)
ss := *(*reflect.StringHeader)(unsafe.Pointer(&s))
// 相同的, 所以是直接转为 字符串 (将字符串的字符数组地址设置为 上面切片的数组地址)
println(unsafe.Pointer(ss.Data), &slice[0])
}2 unsafe.Pointer & uintptr
GC 会管理 unsafe.Pointer uintptr 则不会