Go | unsafe package

Go | unsafe package

1. 简介

unsafe不安全包,可以为我们提供一些Go语言底层的操作。

如:

  • 查找变量占用空间
  • 内存对齐倍数
  • 指针运算
  • 访问非公开的变量

注意:正常我们在开发Go语言程序,应该尽量避免使用该包的内容。

2. 常用方法

2.1. unsafe.Sizeof

简介

计算变量内存中占用字节大小。

示例

func main() {
	var i int32 = 123

	fmt.Println(unsafe.Sizeof(i))  // Output: 4
	fmt.Println(unsafe.Sizeof(&i)) // Output: 8
}

注意

func main() {
	e := struct {
		A *int32
	}{}
	size := unsafe.Sizeof(e)
	fmt.Println(size) // Output: 8
}

2.2. unsafe.Offsetof

简介

计算结构体指针到当前字段内存地址的偏移量,还有可能包含内存对齐产生的空洞。

示例

func main() {
	e1 := struct {
		A int32
		B int32
	}{
		A: 1,
		B: 2,
	}
	offset1 := unsafe.Offsetof(e1.B)
	fmt.Println(offset1) // Output: 4

	e2 := struct {
		A uint8
		B int32
	}{
		A: 1,
		B: 2,
	}
	offset2 := unsafe.Offsetof(e2.B)
	fmt.Println(offset2) // Output: 4
}

2.3. unsafe.Alignof

简介

返回参数需要对齐的倍数。

示例

func main() {
	e := struct {
		A uint8
		B uint32
	}{}
	fmt.Println(unsafe.Alignof(e)) // Output: 4
	fmt.Println(unsafe.Sizeof(e))  // Output: 8
}

2.4. unsafe.Add

简介

指针运算,可以使用usafe.Add进行指针运算达到C/C++指针运算效果。
通过指针运算还可以访问结构体内未开放访问的成员。

示例

func main() {
	example := struct {
		A uint32
		B uint32
		c uint32
	}{
		A: 100,
		B: 101,
		c: 102, // 注意: 小写也可以访问
	}
	a := unsafe.Add(unsafe.Pointer(&example), 0)
	fmt.Println(*(*uint32)(a)) // Output: 100

	b := unsafe.Add(a, 4) // uint32 4个字节
	fmt.Println(*(*uint32)(b)) // Output: 101

	c := unsafe.Add(b, 4) // uint32 4个字节
	fmt.Println(*(*uint32)(c)) // Output: 102
}

遍历slice

// slice 内部实现
type slice struct {
	array unsafe.Pointer // 8 字节
	len   int            // 8 字节
	cap   int            // 8 字节
}

func main() {
	arr := make([]uint32, 2, 4)
	arr[0] = 100
	arr[1] = 101

	// 当前指指针在结构体头
	slicePoint := unsafe.Pointer(&arr)
	// 将指针移动到len启始位置
	lenPoint := unsafe.Add(slicePoint, 8)
	length := *(*int)(lenPoint)
	fmt.Println(length) // Output: 2

	// 将指针移动到cap启始位置
	capPoint := unsafe.Add(lenPoint, 8)
	capacity := *(*int)(capPoint)
	fmt.Println(capacity) // Output: 4

	i := *(*int)(slicePoint)
	p := unsafe.Pointer(uintptr(i))
	// 数组中每个元素
	for i := 0; i < length; i++ {
		item := unsafe.Add(p, i*4)
		fmt.Println(*(*uint32)(item)) // Output: 100 101
	}
}

3. 参考

  • 浅谈Golang的unsafe.Pointer

你可能感兴趣的:(Go,unsafe,go)