Go Unsafe Pointers
An unsafe pointer is a pointer that can point to a value of any type. It comes from the unsafe package, and it lets code reach memory in ways the compiler does not check.
Read and change through a round trip
A pointer to an int converts to unsafe.Pointer and back to a pointer to int. A write through that pointer changes the original value.
package main
import (
"fmt"
"unsafe"
)
func main() {
n := 10
fmt.Println("Before:", n)
p := unsafe.Pointer(&n)
*(*int)(p) = 25
fmt.Println("After:", n)
}Read a field by its offset
uintptr holds an address as a plain number. unsafe.Offsetof gives the distance from the start of a struct to one of its fields. Adding the offset of Y to the address of the struct reaches the Y field.
package main
import (
"fmt"
"unsafe"
)
type Point struct {
X int
Y int
}
func main() {
p := Point{X: 7, Y: 42}
addr := uintptr(unsafe.Pointer(&p)) + unsafe.Offsetof(p.Y)
y := *(*int)(unsafe.Pointer(addr))
fmt.Println(y)
}Read both fields by their offsets
Each field has its own offset from the same starting address. Two reads print both values in field order.
package main
import (
"fmt"
"unsafe"
)
type Point struct {
X int
Y int
}
func main() {
p := Point{X: 7, Y: 42}
base := uintptr(unsafe.Pointer(&p))
x := *(*int)(unsafe.Pointer(base + unsafe.Offsetof(p.X)))
y := *(*int)(unsafe.Pointer(base + unsafe.Offsetof(p.Y)))
fmt.Println(x, y)
}Example
package main
import (
"fmt"
"unsafe"
)
type Point struct {
X int
Y int
}
func main() {
p := Point{X: 1, Y: 2}
addr := uintptr(unsafe.Pointer(&p)) + unsafe.Offsetof(p.Y)
*(*int)(unsafe.Pointer(addr)) = 99
fmt.Printf("%v\n", p)
}Key points
- unsafe.Pointer can hold the address of a value of any type.
- A pointer of any type converts to unsafe.Pointer, and unsafe.Pointer converts back to a pointer of any type.
- uintptr holds an address as a number, so an offset can be added to it.
- unsafe.Offsetof reports the distance in bytes from the start of a struct to one of its fields.
- The compiler does not check this code.
- A mistake can break the program in ways safe code cannot.
In this example, the program builds a Point with X set to 1 and Y set to 2. It adds the offset of Y to the address of the struct. It writes 99 through the pointer at that address. The print shows the whole struct, and Y now holds 99 while X stays 1.
Note
cgo is a tool that calls C code, and it sits outside this course.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Go Playground
Exercise
What happens when code writes through a pointer built from an address plus the offset of the Y field?