Integer sizes and overflow
In the previous lesson, Go's calculator dropped the fractional part when dividing. Now let's look at another of its rules: every integer type has a limited number of digits.
Think of the odometer in an old car. It has six wheels with digits, and it cannot show more than 999999. Drive one more kilometer, and it shows 000000: the wheels rolled over and started again.
Go's integer types work the same way. A variable of type int8 holds numbers from -128 to 127. Adding one to the maximum causes no error: the value moves to the other end of the range.
package main
import "fmt"
func main() {
var x int8 = 127
x++
fmt.Println(x) // -128
}Let's walk through the program line by line:
var x int8 = 127puts intoxthe largest number that fits in anint8.x++increases a variable by one, andx--decreases it. The type stays the same, so the result stays within theint8range.fmt.Println(x)prints-128: the number128does not fit in anint8, and the value moved to the other end of the range.
Here the odometer picture parts ways with Go. An odometer has no negative numbers, but an int8 does. So the maximum is followed not by zero but by the smallest negative number.
Sized types
The digits in a type's name are its number of bits, and a byte has eight bits. The more bytes, the wider the range:
| Type | Bytes | Range |
|---|---|---|
int8 | 1 | from -128 to 127 |
int16 | 2 | from -32768 to 32767 |
int32 | 4 | about ±2.1 billion |
int64 | 8 | about ±9.2 · 10¹⁸ |
uint8 | 1 | from 0 to 255 |
Integer types fall into three groups. Let's take each one.
Signed: int8 to int64
These types hold both positive and negative numbers. About half the range goes to negatives, so an int8 has a minimum of -128 but a maximum of only 127.
You pick such a type when a value can drop below zero: a temperature, the difference of two numbers, a change in a score.
Unsigned: uint8 to uint64
Types that start with the letter u are unsigned: they hold only non-negative numbers, but their maximum is about twice as large.
- Besides
uint8there areuint16,uint32anduint64. byteis another name foruint8.- Every unsigned type has a minimum of
0, so a subtraction can carry it past the lower bound.
The int type
On 64-bit systems and in the course exercises, the int type takes 8 bytes, like int64.
For ordinary integers, use int: its range is almost always enough. Sized types matter when the data format does, for example the bytes of a file are stored as uint8.
Crossing the boundary
When a result does not fit in the type's range, an overflow occurs. What follows depends on when it happens.
At run time
At run time Go does not report an overflow:
- the minimum comes after the maximum: an
int16goes from32767to-32768; - the maximum comes below the minimum: an
int8goes from-128to127; - unsigned types behave the same way: a
uint8goes from255to0, like the odometer.
Press x++ and watch the eight bits of a uint8: carries move right to left, and after 255 every bit becomes zero.
x = 253: a uint8 has eight bits, and the largest number is 255. Press x++.
Interviewers often ask this: what happens when an integer overflows in Go? The answer: the value silently moves to the other end of the range, with no panic and no error.
At build time
The compiler rejects a constant that does not fit in the type:
var b uint8 = 256 // ✗cannot use 256 (untyped int constant) as uint8 value in variable declaration (overflows)The compiler checks only the values known at build time. The statement b++ changes a variable at run time, and there is no such check there.
Common mistake
A quantity that is never negative is stored in an unsigned type, and then something is subtracted from it:
package main
import "fmt"
func main() {
var stock uint8 = 3
stock = stock - 5 // ✗
fmt.Println(stock) // 254
}Neither the compiler nor the program notices an error. The difference 3 - 5 crossed zero downward and became 254, like an odometer wound backward. Store a value that can drop below zero after a subtraction in a signed type, such as int.
Key points
- Every integer type has its own range:
int8holds-128to127,uint8holds0to255. - On overflow at run time, the value silently moves to the other end of the range.
- The compiler rejects a constant that does not fit in the type.
- Use
intfor ordinary numbers, and never keep a value that can drop below zero in an unsigned type.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.