1. Definition and Background of unsafe.Pointer
1 | // ArbitraryType is here for the purposes of documentation only and is not actually |
At its core, unsafe.Pointer is an int-typed pointer that serves as a bridge for converting between different pointer types. Go has a strict type system that intentionally limits pointer operations — you can only operate on the object a pointer refers to, not perform C-style pointer casting or arithmetic. But real-world development sometimes requires breaking out of these constraints to read and write memory directly. As a universal pointer type, unsafe.Pointer opens a back door for low-level pointer operations.
2. Properties of unsafe.Pointer

Any pointer type can be converted to
unsafe.Pointer;unsafe.Pointercan be converted to any pointer type;uintptrcan be converted tounsafe.Pointer;unsafe.Pointercan be converted touintptr;unsafe.Pointeris a universal pointer type, but it only handles type conversion between pointers — it can’t doC-style pointer arithmetic. That’s whereuintptrcomes in. Here’s the official definition:1
2
3// uintptr is an integer type that is large enough to hold the bit pattern of
// any pointer.
type uintptr uintptruintptris an unsigned integer large enough to hold any pointer’s address. It acts as an intermediary, enabling pointer arithmetic and conversions between numeric types and pointer types.
3. Using unsafe.Pointer
3.1 Converting Between Pointer Types
As a universal pointer type, unsafe.Pointer‘s most basic job is bridging conversions between different pointer types. Converting from *X to *Y requires that Y is no larger than X and that both share the same memory layout.

Take byte and string conversion as an example. Go’s type system won’t let you cast a byte pointer directly to a string pointer — the compiler rejects it. We need unsafe.Pointer as an intermediary.
1 | package main |
3.2 Converting Between Numeric Values and Pointers
In C, it’s common to use plain integers to represent pointers. To convert between integers and pointers, unsafe.Pointer alone isn’t enough — we need the middleman uintptr. The pattern is: convert the integer to uintptr first, then to unsafe.Pointer, and finally to the target pointer type. Or in reverse: convert any pointer to unsafe.Pointer, then to uintptr, then to the target integer type. Integer-to-pointer conversion is also one of the key techniques in CGO programming.
Here’s an example converting between int64 and *C.char:

1 | package main |
3.3 Pointer Arithmetic
Go pointers don’t support arithmetic operations either. But with uintptr, you can move pointers around and perform arithmetic.
Here’s an example that prints each byte of a byte slice one at a time:
1 | package main |
4. Summary
unsafe.Pointer exists to bypass Go’s type system and read/write memory directly for performance. As the name suggests, this is unsafe territory. uintptr lacks pointer semantics, so the object it points to risks being collected by the GC. Go strongly discourages these operations — use them only when you have no other choice.