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
u32i 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
isizeusize 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; // errorThis is too large.
Unsigned integers cannot hold negative values.
const x: u8 = -1; // errorInteger 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; // errorYou 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 *% bThere are also saturating operators.
a +| b
a -| b
a *| bSaturating 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.