NOTE

1.8 unsafe

Pointer types in Go, why pointers are needed, the unsafe pointer type, examples, and the underlying APIs.

GoCreated Updated 1 min readhistorical

This is a historical learning note and may contain outdated or incomplete understanding.

1. Pointer Types

1.1. What They Are

The address of a variable.

1.2. Why Pointer Types Are Needed

Using pointer types allows the callee to modify the value passed by the caller.

func double(x int) {
	x += x
}

func main() {
	var a = 3
	double(a)
	fmt.Println(a) // 3
}


// Modified version
func double(x *int) {
	*x += *x
	x = nil
}

func main() {
	var a = 3
	double(&a)
	fmt.Println(a) // 6
	
	p := &a
	double(p)
	fmt.Println(a, p == nil) // 12 false
}

1.3. Golang Pointer Types

Golang pointer types are safe.

  • Mathematical operations cannot be performed on them
  • Pointers of different types cannot be converted into each other
  • Pointers of different types cannot be compared using == or !=
  • Pointer variables of different types cannot be assigned to each other

2. unsafe

2.1. What It Is

An unsafe pointer type.

2.2. Usage

Safe pointer types cannot be used for arithmetic. They can first be converted to unsafe.Pointer, then converted to uintptr for arithmetic.

2.2.1. Get the Length of a slice

func TestUnsafe1(t *testing.T) {
	s := make([]int, 9, 20)
	
    //Len: &s => pointer => uintptr => pointer => *int => int
	var Len = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(8)))
	fmt.Println(Len, len(s))

    //Cap: &s => pointer => uintptr => pointer => *int => int
	var Cap = *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(16)))
	fmt.Println(Cap, cap(s))
}

// output
9 9
20 20

2.2.2. Get the Length of a map

func TestUnsafe2(t *testing.T) {
	mp := make(map[string]int)
	mp["qcrao"] = 100
	mp["stefno"] = 18

	//&mp => pointer => **int => int
	count := **(**int)(unsafe.Pointer(&mp))
	fmt.Println(count, len(mp)) 
}

// output
2 2

2.2.3. Convert between string and []byte

func TestUnsafe3(t *testing.T) {
	bytes := []byte{104, 101, 108, 108, 111}

	p := unsafe.Pointer(&bytes) // forcibly convert to unsafe.Pointer; the compiler will not report an error
	str := *(*string)(p)        // then forcibly convert to a pointer to string, and read the pointed-to value as a string
	fmt.Println(str)            // output "hello
}

2.3. Implementation

  • Data structure
type ArbitraryType int

type Pointer *ArbitraryType// similar to void* in C
  • Methods
// Return the number of bytes occupied by type x, excluding the size of the content pointed to by x
func Sizeof(x ArbitraryType) uintptr
// Return the byte offset of a struct member from the start of the struct; the argument must be a struct member
func Offsetof(x ArbitraryType) uintptr
// Return m, where m means that when a type is memory-aligned, its allocated memory address is divisible by m
func Alignof(x ArbitraryType) uintptr

3. References

Discussion

Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub