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 .

Related Content


Variable vs Constant size

You’ll likely remember that certain built-in functions can sometimes evaluate to constants, rather than variables. For example: var x [10]int var y []int len(x) // evaluates to a constant at compile time len(y) // evaluates to a variable at runtime Package unsafe … A (variable of) type T has variable size if T is a type parameter, or if it is an array or struct type containing elements or fields of variable size.


Context key type: Final recommendation

First, a correction! An astute reader pointed out that I made a small mistake in my post on June, 10, with regard to string context keys. My code example showed: type contextKey string const ( KeyUserID = "user_id" KeyTransactionID = "transaction_id" KeyMessageID = "message_id" ) But it should have been: type contextKey string const ( KeyUserID contextKey = "user_id" KeyTransactionID contextKey = "transaction_id" KeyMessageID contextKey = "message_id" ) This is a nasty kind of bug, because the code will continue to work as expected—just without any protection from key collisions!


Struct context keys

First off, an apology for being rather unreliable with my “daily” emails. I’m in the middle of some traveling (was in the UK and Netherlands last week, and will be on a US road trip starting tomorrow), so I’m writing when I have a spare moment, which isn’t that often. I’ve been talking about finding the ideal type for a context key. So far I’ve looked at empty structs (e.g. struct{}), integers, and strings.

Get daily content like this in your inbox!

Subscribe