What does Go's unsafe.Sizeof(x) return, and is it computed at run time or at compile time?
answer
- the compiler already knows the answer
- no function actually runs for it
- legal where a constant is required
- a uintptr constant, not an int
basics
~20 sunsafe.Sizeof(x) gives the size in bytes of x's own type representation. The compiler replaces the call with a uintptr constant, so no code runs for it and the result never depends on the contents of x.
solid answer
~50 s`unsafe.Sizeof(x)` reports how many bytes a variable of x's type occupies, as if you had written `var v = x` and measured v. It is not an ordinary function call: the compiler folds it into a typed `uintptr` constant, so it costs nothing at run time and may appear anywhere a constant is required, such as an array length or a `const` declaration. Its two siblings work the same way — `unsafe.Alignof(x)` gives the required alignment of that type, and `unsafe.Offsetof(s.f)` gives the byte offset of field `f` from the start of struct `s`. Because the answer is fixed at compile time it measures only the value's own representation and never follows a pointer to count what is on the other end. The one exception to constancy is generic code, where an argument whose type is a type parameter has no compile-time size.
code
go · 11 linestype point struct {
x, y int32
}
var p point
const size = unsafe.Sizeof(p) // a uintptr constant: 8
var _ [unsafe.Sizeof(p)]byte // legal: array lengths must be constant
fmt.Println(unsafe.Sizeof(p)) // 8
fmt.Println(unsafe.Sizeof(int64(0))) // 8go deeper
Be ready to say in one sentence that it reports the byte size of a type and that the compiler works it out, so nothing happens at run time. Knowing that the same number comes back regardless of the value is enough here.
An interviewer expects the mechanics: a typed uintptr constant, usable as an array length or const initialiser, not usable as a function value, and only non-constant when the argument's type is a type parameter.
Show that you know what the number excludes and would never hand it to someone as a memory figure without saying so. Be ready to explain why a struct's size can exceed the sum of its fields.
Own the position on whether layout facts belong in shared code at all: a number baked into a build is an assumption about the target, and it needs an enforcement mechanism and a review policy rather than a comment.
## The three functions The `unsafe` package exposes three measuring operations. Despite their spelling they are not ordinary functions — the compiler recognises the call and substitutes a value: - `unsafe.Sizeof(x) uintptr` — the number of bytes a variable of x's type occupies. - `unsafe.Alignof(x) uintptr` — the required alignment of that type: the largest m such that the address of such a variable is always 0 mod m. - `unsafe.Offsetof(s.f) uintptr` — the byte offset of field `f` measured from the address of the struct denoted by `s`. The language specification defines Sizeof and Alignof in terms of a hypothetical variable: the result is the size or alignment of `v` as if you had written `var v = x`. The value of x is irrelevant; only its type matters. `unsafe.Sizeof("")` and `unsafe.Sizeof("a very long string")` produce the same number, because both are `string` values. ## Compile time, not run time The specification says the results are Go constants of type `uintptr` whenever the argument's type has constant size. That has several practical consequences: 1. **No code executes.** There is no call in the compiled binary, no reflection, no lookup of a type descriptor. The compiler writes a literal into the instruction stream, or more often folds it away entirely. 2. **They work in constant contexts.** `const headerSize = unsafe.Sizeof(x)` is legal, and so is an array type such as `[unsafe.Sizeof(x)]byte`. Ordinary function results cannot be used in either position. This is what makes compile-time size assertions possible. 3. **They cannot be used as values.** `f := unsafe.Sizeof` does not compile; the builtin must be called in place. 4. **The type is `uintptr`, not `int`.** Because the constant is typed, `var n int = unsafe.Sizeof(x)` is rejected — write `int(unsafe.Sizeof(x))`. Functions that accept any integer type, such as `make`, take it directly. The only case where the result is not a constant is a type of variable size, which in practice means a type parameter in generic code (or a type built from one). Inside `func f[T any](v T)`, `unsafe.Sizeof(v)` still yields the right number for each instantiation, but it is not a constant and cannot be an array length. ## What it does and does not measure Sizeof measures the value's own representation — the bytes the variable itself occupies in a struct field, a local slot, or an array element. It never dereferences. For a pointer it reports the size of the pointer, not of the pointee. For types that are internally a pointer plus some bookkeeping words, it reports exactly those words. That is the single most common surprise for people arriving from a language where a size query walks the object graph, and it is why the number is useless as a memory budget without extra work. Also note that the size of a struct is not necessarily the sum of the sizes of its fields: the compiler may insert padding so each field lands on a suitable boundary, and may pad the end of the struct as well. Sizeof reports the real, padded size — the size the compiler will actually reserve. ## Importing unsafe Using these three operations does require importing `unsafe`, which carries a reputation and, in many codebases, a review policy. It is worth knowing that Sizeof, Alignof and Offsetof do not by themselves break any safety guarantee: they produce a number, they never produce a pointer, and they cannot corrupt memory. They are the tamest members of the package, though a build that depends on a particular number is still a build that has made an assumption about its target platform.
- What do unsafe.Alignof and unsafe.Offsetof return, and are they constants too?`unsafe.Alignof(x)` returns the required alignment in bytes of a value of x's type — the largest m for which its address is always 0 mod m. `unsafe.Offsetof(s.f)` takes a selector and returns the byte offset of field `f` from the start of the struct `s` names. Both fold to `uintptr` constants under the same rule as Sizeof.
- Can you store unsafe.Sizeof in a variable and call it later?No. It is a compiler builtin rather than an ordinary function, so `f := unsafe.Sizeof` does not compile — the operation must appear as a complete call, which the compiler then replaces with a constant. The same is true of Alignof and Offsetof.
- Is unsafe.Sizeof ever not a compile-time constant?Yes, when the argument's type has variable size — in practice, a type parameter or a type containing one. Inside a generic function, `unsafe.Sizeof(v)` for a value of type-parameter type still yields the correct size for each instantiation, but it is not a constant and cannot be used as an array length.
It is a measurement taken from the blueprint, not from the finished building: the compiler reads the type and writes down a number, and nobody visits the value.
saying these in an interview costs you the question
- Thinks it is a runtime call that inspects the value
- Expects the result to change with the value's contents
- Says it counts all memory the value can reach
- Assumes the result is an int rather than a uintptr
- Believes it needs reflection or a type descriptor to work