go unsafe

Created

2024-10-28 13:26:19

Updated

2024-10-28 13:26:21

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

func TestSliceData(t *testing.T) {
    slice := []int64{1, 2, 3, 4}
    // unsafe.SliceData 返回指向 切片数据(数组)的指针
    sliceDataPtr := unsafe.SliceData(slice)
    reflSlice := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
    println(sliceDataPtr, unsafe.Pointer(reflSlice.Data))
}

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 则不会

Back to top