> ## Content Index
> Fetch the complete content index at: https://huizhou92.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Decryption go：unsafe.Pointer
- URL: https://huizhou92.com/decryption-go-unsafe-pointer/
- Published: 2024-06-27T08:42:06.000Z
- Updated: 2026-09-06T11:39:15.000Z
- Author: huizhou92
- Tags: tech, golang, #lang-en

## unsafe.Pointer

In the previous article, we compared the differences between three types of pointers in Go. You can check that out before diving into this one. Now, let's summarize the distinctions between the three pointer types.

> - Ordinary pointers: They do not support pointer arithmetic, retain both address and type information, and the data they point to won't be garbage collected.
> - `unsafe.Pointer`: They do not support pointer arithmetic, retain the address but not the type information, and the data they point to won't be garbage collected.
> - `uintptr`: They support address arithmetic, retain the address but not the type information, and the data they point to will be garbage collected.

> This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on [Medium](https://medium.huizhou92.com/?ref=huizhou92.com). Thank you very much.

Compared to C, Go is designed as a strongly-typed statically-typed language for ease of writing, high efficiency, and reduced complexity. Strongly-typed means once defined, a type cannot be changed, while statically-typed means type checking is done before runtime.

For safety reasons, Go doesn't allow conversion between two pointer types. To address this, Go introduces `unsafe.Pointer`. `unsafe.Pointer` is a special kind of pointer that can hold addresses of any type, akin to the void\* pointer in C, being versatile.

## Example

In the [official documentation](https://pkg.go.dev/unsafe?ref=huizhou92.com#Pointer), we find four rules regarding `unsafe.Pointer`:

- Any 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.

With `unsafe.Pointer`, we can achieve conversions between different types.

```go
package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

//go:nosplit
func convert(p *int) *int32 {
	return (*int32)(unsafe.Pointer(p))
}

func main() {
	var i int = 1
	q := convert(&i)
	fmt.Println(reflect.TypeOf(*q))
}

```

Output:

```shell
➜  unsafe git:(main) ✗ go run main.go
int32

```

We've successfully converted variables of different types using `unsafe.Pointer`.

For the third and fourth rules, let's test them with a more complex example.

```go
package main

import (
	"fmt"
	"unsafe"
)

type User struct {
	name string
	age  int32
}

func main() {
	user := &User{
		name: "Tom",
		age:  18,
	}
	fmt.Println(*user)
	pName := (*string)(unsafe.Pointer(user))
	*pName = "Bob"
	age := (*int32)(unsafe.Pointer(uintptr(unsafe.Pointer(user)) + unsafe.Offsetof(user.age)))
	*age = 20
	fmt.Println(*user)
}

```

Output:

```shell
➜  unsafe git:(main) ✗ go run main.go
{Tom 18}
{Bob 20}

```

We've manipulated the values of different fields by offsetting in memory. Firstly, when modifying the `name` field of `user`, since `name` is the first field, no offset is required. We obtain the pointer to `user`, then use `unsafe.Pointer` to convert it to `*string` for the assignment. Secondly, when modifying the `age` field of `user`, we need an offset because `age` isn't the first field. We convert the pointer address of `user` to `uintptr`, then use `unsafe.Offsetof(u.age)` to get the offset needed, perform address arithmetic (+) to offset. Now, the address points to the `age` field of `user`, and to assign it, we need to convert `uintptr` to `*int32`. Thus, by converting `uintptr` to `unsafe.Pointer` and then to `*int32`, we can proceed with the operation. Ultimately, we've achieved pointer operations akin to C in Go.

## Conclusion

`unsafe` is indeed unsafe, hence it should be used sparingly, especially in memory manipulation. This circumvents Go's built-in safety mechanisms and improper operations could lead to memory corruption, which can be very challenging to debug.

`unsafe.Pointer` is mainly used during Go's compilation phase. Because it allows bypassing the type system to directly access memory, it offers higher efficiency. If we decompile the `convert` function, we'd find that it merely changes the MOVQ instruction to MOVL, without introducing any additional instructions.