Integer overflow

February 7, 2024

Integer overflow

For unsigned integer values, the operations +, -, *, and << are computed modulo 2n, where n is the bit width of the unsigned integer’s type. Loosely speaking, these unsigned integer operations discard high bits upon overflow, and programs may rely on “wrap around”.

Let’s illustrate with an example. I’ll use uint8, becuase it’s easier to reason about relatively small numbers, but the same holds for any of the uint family of types.

var x = uint8(254) // Initialize x near the upper limit of uint8's capacity
x++ // Then add one... x = 255, the max value
x++ // Add one more... now the high bits, those that would overflow the 8-bit value, are discarded
fmt.Println(x) // Prints 0
x++ // Add one more...
fmt.Println(x) // Prints 1

This program prints the following output, fully demonstrating that adding to a fixed-length unsigned integer “overflows”, starting again at 0.


For signed integers, the operations +, -, *, /, and << may legally overflow and the resulting value exists and is deterministically defined by the signed integer representation, the operation, and its operands. Overflow does not cause a run-time panic. A compiler may not optimize code under the assumption that overflow does not occur. For instance, it may not assume that x < x + 1 is always true.

This will likely be a bit more confusing to many of you. Let’s modify the above code example to use int8 instead of uint8:

var x = int8(126)

Now it prints:


What tha…

To understand how the result is “deterministicly defined”, you’ll need an understanding of two’s compliment math, which is beyond the scope of this email series to fully explain. But Wikipedia can help you out if you’re really interested!

Quotes from The Go Programming Language Specification Version of August 2, 2023

Share this

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

Unsure? Browse the archive .