- read

What is unsafe.Pointer, or uintptr?

Phuong Le (@func25) 45

GO ADVANCED

Photo by Mark König on Unsplash

unsafe.Pointer, uintptr seem like total black magic to many Go developers. We often just use them as special spells for packages without really understanding how they work under the hood.

And admittedly, they are seriously magical, let me show you an example of how I can use unsafe pointers to rejuvenate a person.

type Person struct {
Name string
age int
}

func main() {
person := Person{Name: "John", age: 30}

// Cast name to unsafe pointer
namePtr := unsafe.Pointer(&person.Name)
nameSize := unsafe.Sizeof(person.Name)

p := (*int)(unsafe.Add(namePtr, nameSize))
*p = 10

fmt.Println(person) // {John 10}
}

By doing some unsafe pointer math, I can modify the private age field through the public Name field. This approach is totally unintuitive, but it works, changing John’s age from 30 to 10.

Understanding how to safely leverage unsafe pointers enables building powerful functionality.

First look at unsafe package

Beside unsafe.Pointer, this package provide us several functions provide low-level information, make us understand more about the internal structure of type.

unsafe.Alignof

The alignment is a concept which bring from the low-level programming, it returns the required alignment of a type and the layout of memory can affect the performance of our application.

For example, an int32 has an alignment of 4 bytes. The alignment of a struct depends on the field with the largest alignment:

type Person struct {
Name string
age int
}

func main() {
var i int32 = 1
var s [3]int8 = [3]int8{1, 2, 3}
var p Person = Person{"Bob", 20}

fmt.Println("aligno(int32) =", unsafe.Alignof(i))
fmt.Println("alignof([]int8) =", unsafe.Alignof(s))
fmt.Println("alignof(Person) =", unsafe.Alignof(p))
}

// aligno(int32) = 4
// alignof([3]int8) = 1
// alignof(Person) = 8