Integer Types
Zig has signed and unsigned integer types.
Integer Types
Zig has signed and unsigned integer types.
A signed integer can hold negative and positive values.
const a: i32 = -10;
An unsigned integer can hold only zero and positive values.
const b: u32 = 10;
The letter tells whether the integer is signed or unsigned.
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.
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.
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.
const x = 10;
The compiler gives x a type from context. When the context is explicit, the type is clear.
const x: i32 = 10;
const y: u8 = 10;
A value must fit in its type.
const x: u8 = 255;
This is valid. The largest value of u8 is 255.
const x: u8 = 256; // error
This is too large.
Unsigned integers cannot hold negative values.
const x: u8 = -1; // error
Integer arithmetic uses the type of the operands.
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.
const a: i32 = 10;
const b: u32 = 20;
const c = a + b; // error
You must convert explicitly.
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.
const byte: u8 = 0xff;
For ordinary arithmetic, use a type that fits the problem clearly.
const count: u32 = 1000;
const total: u64 = 1_000_000;
Underscores may be used to make large numbers easier to read.
const n = 1_000_000;
They do not change the value.
Integer literals may also be written in other bases.
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.
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.
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.
a +% b
a -% b
a *% b
There are also saturating operators.
a +| b
a -| b
a *| b
Saturating arithmetic stops at the minimum or maximum value instead of wrapping.
For example, with u8:
var x: u8 = 255;
x +|= 1;
x remains 255.
Use plain arithmetic unless the program specifically needs wrapping or saturation.
Exercises:
-
Declare an
i32with value-100and print it. -
Declare a
u8with value255. Try assigning256and read the compiler error. -
Write a loop over an array using
usizeas the index type. -
Write the value
255in decimal, hexadecimal, binary, and octal. -
Compare
+,+%, and+|onu8values near255.