# Integer Types

### Integer Types

Zig has signed and unsigned integer types.

A signed integer can hold negative and positive values.

```zig
const a: i32 = -10;
```

An unsigned integer can hold only zero and positive values.

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

The letter tells whether the integer is signed or unsigned.

```zig
i32
u32
```

`i` means signed integer.  
`u` means unsigned integer.  
`32` means 32 bits.

Common integer types are:

| Type | Meaning |
|---|---|
| `i8` | signed 8-bit integer |
| `u8` | unsigned 8-bit integer |
| `i16` | signed 16-bit integer |
| `u16` | unsigned 16-bit integer |
| `i32` | signed 32-bit integer |
| `u32` | unsigned 32-bit integer |
| `i64` | signed 64-bit integer |
| `u64` | unsigned 64-bit integer |
| `i128` | signed 128-bit integer |
| `u128` | unsigned 128-bit integer |

There are also machine-sized integer types.

```zig
usize
isize
```

`usize` is an unsigned integer large enough to hold the size of memory on the target machine. It is commonly used for indexes, lengths, and sizes.

```zig
const data = [_]u8{ 10, 20, 30 };

var i: usize = 0;
while (i < data.len) : (i += 1) {
    // use data[i]
}
```

Integer literals do not have a fixed type by themselves.

```zig
const x = 10;
```

The compiler gives `x` a type from context. When the context is explicit, the type is clear.

```zig
const x: i32 = 10;
const y: u8 = 10;
```

A value must fit in its type.

```zig
const x: u8 = 255;
```

This is valid. The largest value of `u8` is `255`.

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

This is too large.

Unsigned integers cannot hold negative values.

```zig
const x: u8 = -1; // error
```

Integer arithmetic uses the type of the operands.

```zig
const a: i32 = 10;
const b: i32 = 20;
const c = a + b;
```

Here `c` is an `i32`.

Zig does not silently mix different integer types.

```zig
const a: i32 = 10;
const b: u32 = 20;

const c = a + b; // error
```

You must convert explicitly.

```zig
const a: i32 = 10;
const b: u32 = 20;

const c = a + @as(i32, @intCast(b));
```

`@intCast` checks that the value can fit in the destination type. `@as` supplies the destination type when the context is not enough.

Small integer types are useful when the size is part of the data format.

```zig
const byte: u8 = 0xff;
```

For ordinary arithmetic, use a type that fits the problem clearly.

```zig
const count: u32 = 1000;
const total: u64 = 1_000_000;
```

Underscores may be used to make large numbers easier to read.

```zig
const n = 1_000_000;
```

They do not change the value.

Integer literals may also be written in other bases.

```zig
const decimal = 255;
const hex = 0xff;
const binary = 0b1111_1111;
const octal = 0o377;
```

All four constants have the same value.

Overflow is checked in safe build modes.

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

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

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

In a checked build, this traps because `255 + 1` cannot fit in `u8`.

When wrapping behavior is intended, use wrapping operators.

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

Now `x` becomes `0`.

Zig makes overflow visible. Plain `+` means ordinary integer addition with safety checks when enabled. `+%` means wrapping addition.

Other wrapping operators follow the same pattern.

```zig
a +% b
a -% b
a *% b
```

There are also saturating operators.

```zig
a +| b
a -| b
a *| b
```

Saturating arithmetic stops at the minimum or maximum value instead of wrapping.

For example, with `u8`:

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

`x` remains `255`.

Use plain arithmetic unless the program specifically needs wrapping or saturation.

Exercises:

1. Declare an `i32` with value `-100` and print it.

2. Declare a `u8` with value `255`. Try assigning `256` and read the compiler error.

3. Write a loop over an array using `usize` as the index type.

4. Write the value `255` in decimal, hexadecimal, binary, and octal.

5. Compare `+`, `+%`, and `+|` on `u8` values near `255`.

