Integer Rules
const std = @import("std");
const expect = std.testing.expect;
test "arbitrary bit widths" {
// Any width from u0/i0 up to u65535 is a real type.
const small: u3 = 7;
try expect(@as(u8, small) == 7);
try expect(std.math.maxInt(u3) == 7);
}
test "widening is implicit, narrowing is not" {
const a: u8 = 200;
const b: u16 = a; // always safe, so allowed
try expect(b == 200);
// `const c: u8 = b;` would not compile. Say what you mean:
const c: u8 = @intCast(b); // checked in safety builds
try expect(c == 200);
}
test "wrapping and saturating operators" {
const max: u8 = 255;
// Plain `max + 1` is illegal behaviour (a panic in safety builds).
try expect(max +% 1 == 0); // wrapping
try expect(max +| 1 == 255); // saturating
}
test "overflow can be detected instead" {
const max: u8 = 255;
const result = @addWithOverflow(max, 1);
try expect(result[0] == 0); // wrapped value
try expect(result[1] == 1); // overflow bit set
}
test "comptime_int has no width" {
// Literals are arbitrary precision until they are given a type.
const big = 1 << 100;
try expect(big > 0);
try expect(@TypeOf(1 + 1) == comptime_int);
}Any width you like
u3, i7, u64, u1000 are all real types. u8 is not special, it is just
the one that happens to be a byte. Packed structs use this to describe bitfields
exactly.
Widening is free, narrowing is not
u8 → u16 is always safe, so Zig does it implicitly. The reverse can lose
data, so it must be written:
const c: u8 = @intCast(b);
In a safety-enabled build @intCast panics if the value does not fit. In
ReleaseFast it is illegal behaviour. Either way, the cast is visible in the
source, so you cannot lose the top bits by accident.
Overflow is a decision
Plain + on integers traps on overflow rather than wrapping. If you want
different behaviour, ask for it:
| Operator | On overflow |
|---|---|
+ - * | illegal behaviour (panics in safety builds) |
+% -% *% | wrap around |
+| -| *| | saturate at the type’s limit |
Or detect it: @addWithOverflow(a, b) returns a tuple of the wrapped result
and an overflow bit.
This is C’s biggest silent-corruption source turned into an explicit choice.
comptime_int
Literals have no width until they are assigned one. 1 << 100 is fine at
compile time; it only needs to fit once it becomes a runtime value.