go 使用 unsafe 包

发布时间 2023-06-25 11:55:20作者: CK..Soul

go 使用 unsafe 包进行指针操作

go 语言中没有直接提供指针操作,但是提供了 unsafe 包可以对指针进行转换

//	- A pointer value of any type can be converted to a Pointer.
//	- A Pointer can be converted to a pointer value of any type.
//	- A uintptr can be converted to a Pointer.
//	- A Pointer can be converted to a uintptr.

前置知识

unsafe 包中几个类型的定义

package unsafe

// ArbitraryType is here for the purposes of documentation only and is not actually
// part of the unsafe package. It represents the type of an arbitrary Go expression.
type ArbitraryType int

// IntegerType is here for the purposes of documentation only and is not actually
// part of the unsafe package. It represents any arbitrary integer type.
type IntegerType int

type Pointer *ArbitraryType

uintptr 类型的定义

// uintptr is an integer type that is large enough to hold the bit pattern of
// any pointer.
type uintptr uintptr

提供的指针操作

官方文档一共提供有四中方式

  1. 指针转换成 Pointer; *T -> Pointer
  2. Pointer 转换成指针; Pointer -> *T
  3. uintptr 转换成Pointer; uintptr -> Pointer
  4. Pointer 转换成uintptr; Pointer -> uintptr

普罗米修斯监控中,使用 uint64 来代表 float64 的存储,

type histogramCounts struct {
	// sumBits contains the bits of the float64 representing the sum of all
	// observations. sumBits and count have to go first in the struct to
	// guarantee alignment for atomic operations.
	// http://golang.org/pkg/sync/atomic/#pkg-note-BUG
	sumBits uint64
	count   uint64
	buckets []uint64
}
func Float64bits(f float64) uint64 {
    return *(*uint64)(unsafe.Pointer(&f))
}

指针加减来获取数组的值

func TestXx1(t *testing.T) {
	var a int = 5
	var b float64 = 5.99
	var c [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	var f Foo

	var p1 = (unsafe.Pointer)(&a)
	var p2 = (unsafe.Pointer)(&b)
	var p3 = (unsafe.Pointer)(&c)
	var p4 = (unsafe.Pointer)(&f)
	t.Log(p1, p2, p3, p4)

	for i := 0; i < len(c); i++ {

		pp := unsafe.Pointer((uintptr(p3) + uintptr(i)*unsafe.Sizeof(c[i]))) // 当前下标对应的地址

		pt := *(*int)(pp) + 3
		*(*int)(pp) = *(*int)(pp) + 1 // 重新设置值

		t.Log(pp, " => ", *(*int)(pp), pt, "    => ", c[i], "   => ", uintptr(i))

	}
}

执行结果
img


判断当前结构体是否实现接口

type test struct{}
type i interface {
	Name() string
}

func (*test) Name() string {
	return "test"
}
func TestIsImp(t *testing.T) {

	var _ i = (*test)(nil) // 如果未实现,在编译时就会报错
	var tt i = &test{}

	t.Log(tt.Name())
}

字符串转换


func TestS2B(t *testing.T) {
	var s = "123456"
	t.Log((*[]byte)(unsafe.Pointer(&s)))
	t.Log(*(*[]byte)(unsafe.Pointer(&s)))
}