# Integer Types and Overflow

### Integer Types and Overflow

Integers are whole numbers.

```zig
const a = 10;
const b = -5;
const c = 0;
```

Zig has many integer types because systems programs often need exact control over size. A number might be stored in one byte, four bytes, eight bytes, or some unusual number of bits. Zig lets you say exactly what you want.

#### Signed and unsigned integers

Integer types usually start with either `i` or `u`.

```zig
const x: i32 = -100;
const y: u32 = 100;
```

`i32` means a signed 32-bit integer. It can store negative numbers, zero, and positive numbers.

`u32` means an unsigned 32-bit integer. It can store only zero and positive numbers.

The same pattern works for other sizes:

| Type | Meaning | Can store negative values |
|---|---|---|
| `i8` | signed 8-bit integer | yes |
| `u8` | unsigned 8-bit integer | no |
| `i16` | signed 16-bit integer | yes |
| `u16` | unsigned 16-bit integer | no |
| `i32` | signed 32-bit integer | yes |
| `u32` | unsigned 32-bit integer | no |
| `i64` | signed 64-bit integer | yes |
| `u64` | unsigned 64-bit integer | no |

A bit is a binary digit. It can be `0` or `1`. An 8-bit integer uses 8 binary digits. A 32-bit integer uses 32 binary digits.

#### Ranges

The number of bits decides how many values the type can store.

A `u8` has 8 bits. It can store 256 different values:

```text
0 through 255
```

An `i8` also has 8 bits, but it must include negative numbers too:

```text
-128 through 127
```

This code is valid:

```zig
const a: u8 = 255;
const b: i8 = -128;
```

This code is invalid:

```zig
const a: u8 = 256;  // too large
const b: i8 = 128;  // too large
const c: u8 = -1;   // unsigned integers cannot be negative
```

Zig checks these cases. If a value cannot fit into the type, the compiler rejects it.

#### Arbitrary bit-width integers

Zig also supports integer types with custom bit widths.

```zig
const small: u3 = 5;
```

`u3` is an unsigned 3-bit integer. It can store values from `0` to `7`.

```text
000 = 0
001 = 1
010 = 2
011 = 3
100 = 4
101 = 5
110 = 6
111 = 7
```

This is valid:

```zig
const x: u3 = 7;
```

This is invalid:

```zig
const x: u3 = 8; // error
```

Custom-width integers are useful in packed data structures, hardware programming, binary protocols, and file formats. Beginners do not need them often, but they show one of Zig’s goals: exact control over representation.

#### `usize` and `isize`

Zig has two pointer-sized integer types:

```zig
usize
isize
```

`usize` is an unsigned integer large enough to hold a memory size or array index on the target platform.

`isize` is the signed version.

You will see `usize` often with arrays and slices:

```zig
const index: usize = 0;
```

When you write loops over arrays, indexes are commonly `usize`.

```zig
const std = @import("std");

pub fn main() void {
    const numbers = [_]i32{ 10, 20, 30 };

    var i: usize = 0;
    while (i < numbers.len) : (i += 1) {
        std.debug.print("{}\n", .{numbers[i]});
    }
}
```

`numbers.len` has type `usize`, so the index `i` is also a `usize`.

#### Integer literals

A number written directly in source code is called an integer literal.

```zig
const x = 123;
```

The literal `123` does not immediately have a fixed machine integer type like `i32` or `u64`. Zig can keep it as a compile-time integer until a specific type is needed.

For example:

```zig
const a: u8 = 123;
const b: i32 = 123;
const c: u64 = 123;
```

The same literal can be used in different contexts because `123` fits into all those types.

But this fails:

```zig
const x: u8 = 300; // error
```

`300` does not fit into `u8`.

#### Number bases

Zig lets you write integers in different bases.

```zig
const decimal = 255;
const binary = 0b11111111;
const octal = 0o377;
const hexadecimal = 0xff;
```

All four values mean the same number: `255`.

Different bases are useful in different contexts.

Binary is useful when thinking about individual bits:

```zig
const flags = 0b1010;
```

Hexadecimal is common in systems programming because one hex digit represents exactly 4 bits:

```zig
const color = 0xff00aa;
const mask = 0xffff0000;
```

You can also use underscores to make large numbers easier to read:

```zig
const one_million = 1_000_000;
const mask = 0xffff_0000;
```

The underscores do not change the value.

#### Basic arithmetic

Integer arithmetic works as expected:

```zig
const a: i32 = 10;
const b: i32 = 3;

const sum = a + b;
const difference = a - b;
const product = a * b;
const quotient = @divTrunc(a, b);
```

Zig is explicit about some forms of division. For signed integers, you often use builtins such as `@divTrunc`, `@divFloor`, or `@divExact`, depending on the behavior you want.

For unsigned integers, normal division is simpler:

```zig
const a: u32 = 10;
const b: u32 = 3;

const q = a / b; // 3
```

The result is an integer. The fractional part is discarded.

#### Overflow

Overflow happens when a calculation produces a number too large or too small for the type.

Consider `u8`.

```text
minimum: 0
maximum: 255
```

Now look at this:

```zig
var x: u8 = 255;
x = x + 1;
```

Mathematically, `255 + 1` is `256`.

But `u8` cannot store `256`.

That is overflow.

In safe build modes, Zig checks for overflow and stops the program if overflow happens at runtime. At compile time, Zig rejects overflow when it can prove it.

```zig
const x: u8 = 255 + 1; // error
```

This is a major safety feature. In C, unsigned overflow wraps around by default. In Zig, ordinary arithmetic is checked in safety-enabled modes.

#### Wrapping arithmetic

Sometimes overflow is intentional.

For example, low-level code may want values to wrap around like a clock:

```text
254, 255, 0, 1, 2
```

Zig makes this explicit with wrapping operators.

```zig
var x: u8 = 255;
x +%= 1;
```

After this, `x` becomes `0`.

Wrapping operators include:

| Operator | Meaning |
|---|---|
| `+%` | wrapping addition |
| `-%` | wrapping subtraction |
| `*%` | wrapping multiplication |
| `+%=` | wrapping addition assignment |
| `-%=` | wrapping subtraction assignment |
| `*%=` | wrapping multiplication assignment |

Example:

```zig
const std = @import("std");

pub fn main() void {
    var x: u8 = 255;
    x +%= 1;

    std.debug.print("{}\n", .{x});
}
```

Output:

```text
0
```

The important point is that wrapping is visible in the code. A reader can see that overflow is intentional.

#### Saturating arithmetic

Sometimes you want a value to stop at the minimum or maximum instead of overflowing.

For example:

```text
250 + 10 = 255
```

for a `u8`, because `255` is the maximum.

This is called saturating arithmetic.

Zig has saturating operators:

| Operator | Meaning |
|---|---|
| `+|` | saturating addition |
| `-|` | saturating subtraction |
| `*|` | saturating multiplication |
| `+|=` | saturating addition assignment |
| `-|=` | saturating subtraction assignment |
| `*|=` | saturating multiplication assignment |

Example:

```zig
const std = @import("std");

pub fn main() void {
    var x: u8 = 250;
    x +|= 10;

    std.debug.print("{}\n", .{x});
}
```

Output:

```text
255
```

The value stops at the maximum instead of wrapping to a small number.

#### Bitwise operations

Integers can also be treated as groups of bits.

Zig supports common bitwise operators:

| Operator | Meaning |
|---|---|
| `&` | bitwise AND |
| `|` | bitwise OR |
| `^` | bitwise XOR |
| `~` | bitwise NOT |
| `<<` | shift left |
| `>>` | shift right |

Example:

```zig
const a: u8 = 0b1100;
const b: u8 = 0b1010;

const both = a & b;   // 0b1000
const either = a | b; // 0b1110
const diff = a ^ b;   // 0b0110
```

Bitwise operations are common in flags, compression, encryption, binary formats, and hardware registers.

For now, you only need the basic idea: integers can represent numbers, but they can also represent raw bit patterns.

#### Casting integers

Sometimes you need to convert one integer type to another.

```zig
const small: u8 = 10;
const large: u32 = small;
```

Going from a smaller type to a larger compatible type is usually safe.

Going from a larger type to a smaller type may lose information, so Zig requires an explicit cast.

```zig
const large: u32 = 200;
const small: u8 = @intCast(large);
```

If the value does not fit, safety checks can catch the problem.

```zig
const large: u32 = 1000;
const small: u8 = @intCast(large); // too large for u8
```

Zig wants narrowing conversions to be visible.

#### Choosing integer types

For ordinary beginner code, these are reasonable defaults:

| Use case | Type |
|---|---|
| array index | `usize` |
| count or size | `usize` |
| small byte value | `u8` |
| general signed integer | `i32` or `i64` |
| general unsigned integer | `u32` or `u64` |
| exact binary field | exact size, such as `u16` or `u32` |

Do not overthink every small number at first. But when size, layout, or range matters, choose the type deliberately.

#### The main idea

Integer types in Zig are precise.

A type like `u8` does not mean “some small number.” It means exactly an unsigned 8-bit integer. It has a fixed range. It has specific overflow behavior. It has a specific memory representation.

Zig makes these details visible because systems code depends on them.

