ZetCode

Golang uintptr type

last modified May 8, 2025

This tutorial explains how to use the uintptr built-in type in Go. We'll cover low-level pointer operations with practical examples of memory address manipulation.

The uintptr is an integer type that is large enough to hold the bit pattern of any pointer. It's primarily used for unsafe pointer arithmetic when interacting with system calls or C libraries.

In Go, uintptr is often used with the unsafe package for low-level programming. It represents memory addresses as unsigned integers, allowing arithmetic operations on pointers.

Basic uintptr usage

This example demonstrates converting a pointer to uintptr and back. It shows the basic relationship between pointers and uintptr values.
Note: These operations require the unsafe package.

basic_uintptr.go
package main

import (
    "fmt"
    "unsafe"
)

func main() {

    var x int = 42
    ptr := &x
    
    // Convert pointer to uintptr
    addr := uintptr(unsafe.Pointer(ptr))
    
    fmt.Printf("Pointer: %p\n", ptr)
    fmt.Printf("Address as uintptr: 0x%x\n", addr)
    
    // Convert back to pointer
    newPtr := (*int)(unsafe.Pointer(addr))
    fmt.Println("Value through new pointer:", *newPtr)
}

The code converts a pointer to uintptr and back safely. The uintptr holds the memory address as an integer value, which can be printed or manipulated.

Pointer arithmetic with uintptr

This example shows how to perform pointer arithmetic using uintptr to access struct fields. It demonstrates calculating field offsets.

pointer_arithmetic.go
package main

import (
    "fmt"
    "unsafe"
)

type Person struct {
    name string
    age  int
}

func main() {

    p := Person{"Alice", 30}
    base := unsafe.Pointer(&p)
    
    // Calculate name field address
    namePtr := (*string)(unsafe.Pointer(base))
    fmt.Println("Name:", *namePtr)
    
    // Calculate age field address
    agePtr := (*int)(unsafe.Pointer(uintptr(base) + unsafe.Offsetof(p.age)))
    fmt.Println("Age:", *agePtr)
}

The code uses uintptr arithmetic to access struct fields directly. The unsafe.Offsetof function helps calculate field offsets safely.

Converting between uintptr and unsafe.Pointer

This example demonstrates proper conversion patterns between uintptr and unsafe.Pointer. It shows temporary uintptr usage in a single expression.

conversion_patterns.go
package main

import (
    "fmt"
    "unsafe"
)

func main() {

    data := []byte{'G', 'o', 'l', 'a', 'n', 'g'}
    
    // Safe conversion pattern
    firstChar := *(*byte)(unsafe.Pointer(
        uintptr(unsafe.Pointer(&data[0]))))
    
    // Unsafe pattern (don't do this)
    // addr := uintptr(unsafe.Pointer(&data[0]))
    // ... potential GC here ...
    // firstChar := *(*byte)(unsafe.Pointer(addr))
    
    fmt.Printf("First character: %c\n", firstChar)
}

The safe pattern keeps the conversion in one expression. Storing uintptr in variables can lead to issues if garbage collection occurs.

System call with uintptr

This example shows uintptr usage in system calls, where memory addresses must be passed as integers. It demonstrates Windows API call pattern.

syscall_example.go
package main

import (
    "fmt"
    "syscall"
    "unsafe"
)

func main() {

    user32 := syscall.NewLazyDLL("user32.dll")
    msgBox := user32.NewProc("MessageBoxW")
    
    text, _ := syscall.UTF16PtrFromString("Hello from Go!")
    caption, _ := syscall.UTF16PtrFromString("uintptr Example")
    
    // Convert pointers to uintptr for syscall
    ret, _, _ := msgBox.Call(
        0,
        uintptr(unsafe.Pointer(text)),
        uintptr(unsafe.Pointer(caption)),
        0)
    
    fmt.Printf("MessageBox returned: %d\n", ret)
}

The syscall requires uintptr arguments. The code converts string pointers to uintptr values for the Windows API call. This is a common pattern in FFI.

Memory inspection with uintptr

This example demonstrates using uintptr to inspect memory layout. It shows how to examine the internal structure of a slice.

memory_inspection.go
package main

import (
    "fmt"
    "unsafe"
)

func main() {

    s := []int{10, 20, 30}
    
    // Get slice header
    header := (*[3]uintptr)(unsafe.Pointer(&s))
    
    // Extract slice components
    ptr := header[0]
    len := header[1]
    cap := header[2]
    
    fmt.Printf("Pointer: 0x%x\n", ptr)
    fmt.Printf("Length: %d\n", len)
    fmt.Printf("Capacity: %d\n", cap)
    
    // Access first element
    first := *(*int)(unsafe.Pointer(ptr))
    fmt.Println("First element:", first)
}

The code uses uintptr to examine the slice header structure. This reveals the underlying array pointer, length, and capacity values stored in the slice.

Source

Go language specification

This tutorial covered the uintptr type in Go with practical examples of low-level memory operations and system interactions.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Golang tutorials.