Offsetof

January 10, 2025

Package unsafe

The function Offsetof takes a (possibly parenthesized) selector s.f, denoting a field f of the struct denoted by s or *s, and returns the field offset in bytes relative to the struct’s address. If f is an embedded field, it must be reachable without pointer indirections through fields of the struct. For a struct s with field f:

uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f) == uintptr(unsafe.Pointer(&s.f))

I expect this is neither too confusing, nor too useful for most of us. But let’s use an example to make it glaringly obvious, just the same.

Let’s recall what we learned Wednesday about Sizeof, and apply it to a struct:

type X struct {
	A int
	B string
	C float64
}
var x X
fmt.Println("X:"unsafe.Sizeof(x))
fmt.Println("X.A:", unsafe.Sizeof(x.A))
fmt.Println("X.B:", unsafe.Sizeof(x.B))
fmt.Println("xX.C:", unsafe.Sizeof(x.C))

On a 64-bit system, this little program should output:

X: 32
X.A: 8
X.B: 16
X.C: 8

So now, what are the offsets of x.A, x.B, and x.C? Simple arithmetic would suggest: 0, 0 + 8 (8), and 0 + 8 + 16 (24) respectively. Let’s see:

fmt.Println("X.A offset:", unsafe.Offsetof(x.A))
fmt.Println("X.B offset:", unsafe.Offsetof(x.B))
fmt.Println("X.C offset:", unsafe.Offsetof(x.C))

And indeed, we find the output is:

X.A offset: 0
X.B offset: 8
X.C offset: 24

Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Get daily content like this in your inbox!

Subscribe