Pointer Arithmetic

I mentioned a few days ago that pointer arithmetic is possible through the unsafe package. Here’s how to do it. Package unsafe … The function Add adds len to ptr and returns the updated pointer unsafe.Pointer(uintptr(ptr) + uintptr(len)) [Go 1.17]. The len argument must be of integer type or an untyped constant. A constant len argument must be representable by a value of type int; if it is an untyped constant it is given type int.


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.


Variable Alignment

Package unsafe … Computer architectures may require memory addresses to be aligned; that is, for addresses of a variable to be a multiple of a factor, the variable’s type’s alignment. The function Alignof takes an expression denoting a variable of any type and returns the alignment of the (type of the) variable in bytes. For a variable x: uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0 I don’t think I’m qualified to really talk much more about this.


Offsetof

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.

Subscribe to Boldly Go: Daily

Every day I'll send you advice to improve your understanding of Go. Don't miss out! I will respect your inbox, and honor my privacy policy.

Unsure? Browse the archive.


Determining the size of a variable

Package unsafe … The functions Alignof and Sizeof take an expression x of any type and return the alignment or size, respectively, of a hypothetical variable v as if v was declared via var v = x. Grammar nit! That should be “…as if v were…” But nobody cares about that. While Alignof is unlikely to be used outside of CGO, or low-level optimizations, Sizeof can be useful for us mere mortals.


Package unsafe

Today we’re venturing into dangerous territory… the unsafe package! You can go years working in Go (as I have) without ever using unsafe, or just barely bumping into it. On the other hand, somd developers spend significant time using unsafe, to get the utmost performance out of their code, by working around the type system. Using unsafe can be powerful and beneficial. But… do it with the understanding that you’re giving up the benefits of memory and type safety, and cross-platform compatibility.


Run-time panics

Run-time panics Execution errors such as attempting to index an array out of bounds trigger a run-time panic equivalent to a call of the built-in function panic with a value of the implementation-defined interface type runtime.Error. That type satisfies the predeclared interface type error. The exact error values that represent distinct run-time error conditions are unspecified. package runtime type Error interface { error // and perhaps other methods } We’ve already covered the built-in panic function, and the related recover.


Errors

Today we’re looking at errors, and the built-in error interface. For a concept that’s so central to the Go ethos, the spec has surprisingly little to say about it: Errors The predeclared type error is defined as type error interface { Error() string } It is the conventional interface for representing an error condition, with the nil value representing no error. For instance, a function to read data from a file might be defined:


Program execution

Program execution A complete program is created by linking a single, unimported package called the main package with all the packages it imports, transitively. The main package must have package name main and declare a function main that takes no arguments and returns no value. func main() { … } Program execution begins by initializing the program and then invoking the function main in package main. When that function invocation returns, the program exits.


Happy New Year!

I’ve been on an unannounced, unplanned, month-long hiatus, what with moving my family across the globe. But with the new year starting, and the worst of the chaos behind me, I’m going to try to get back in the saddle again, and pick up where I left off. And what better way to initialize 2025 than with talking about init? Program initialization … Package initialization—variable initialization and the invocation of init functions—happens in a single goroutine, sequentially, one package at a time.


Program initialization

I wasn’t exactly planning to take last week off from the daily emails, but with Thanksgiving preparations, and still living out of a suitcase, it just happened that way. But I’m back now, and ready to talk about Program initialization Program initialization The packages of a complete program are initialized stepwise, one package at a time. If a package has imports, the imported packages are initialized before initializing the package itself.