Operators in Zig
Explore arithmetic, comparison, logical, bitwise, and Zig-specific wrapping and saturating operators with runnable Docker examples
Operators are the verbs of a programming language — they describe what to do with the values your variables hold. Because Zig is a systems language with a “no hidden control flow” philosophy, its operators behave exactly as written: there is no operator overloading, no implicit numeric conversions, and no hidden allocations behind an expression.
Zig also exposes operators that most high-level languages hide: wrapping arithmetic for when you actually want modular overflow, saturating arithmetic for when you want to clamp at a limit, and built-in functions like @divTrunc and @rem for cases where the right behavior is ambiguous for signed integers.
This tutorial walks through Zig’s operator categories with a single runnable program so you can see how each one behaves in practice.
Arithmetic, Wrapping, and Saturating Operators
Zig’s standard arithmetic operators (+, -, *, /, %) check for overflow in debug builds. For signed integers, / and % are only allowed when the operands divide evenly — otherwise you must use @divTrunc, @divFloor, or @rem to make your intent explicit.
For situations where you want overflow to wrap around (common in hashing or fixed-width arithmetic), Zig provides the +%, -%, and *% operators. For situations where you want the value to clamp at the type’s minimum or maximum, use the saturating variants +|, -|, and *|.
Create a file named operators.zig:
| |
A few notes on what makes this code distinctly Zig:
@divTruncand@remare built-in functions, not operators. Zig forces you to pick a rounding mode (@divTrunc,@divFloor,@divExact) for signed integer division so the behavior at negative inputs is never ambiguous.+%and+|are first-class operators in the grammar — overflow handling is part of the language, not a library function.++and**work on arrays and strings at compile time only; the operands must becomptime-known values.orelseis the operator for unwrapping optional types (?T) with a default value.
Running with Docker
| |
Expected Output
a + b = 22
a - b = 12
a * b = 85
@divTrunc = 3
@rem = 2
x / y = 3.40
255 +% 1 = 0
255 +| 10 = 255
a == b = false
a != b = true
a > b = true
t and f = false
t or f = true
!t = false
m & n = 1000
m | n = 1110
m ^ n = 110
m << 1 = 11000
Hello, Zig!
------------
maybe orelse 0 = 42
null orelse 0 = 0
Operator Precedence
Zig has fewer precedence levels than C and avoids the most error-prone ambiguities. A few rules worth remembering:
- Unary operators (
-,!,~) bind tighter than any binary operator. - Multiplicative operators (
*,/,%,**) bind tighter than additive operators (+,-,++). - Bit-shift operators (
<<,>>) sit between additive and bitwise tiers. - Bitwise operators (
&,|,^) share a single tier along withorelseandcatch— lower than shifts but higher than comparisons. - Comparison operators (
==,!=,<,>,<=,>=) cannot be chained;a < b < cis a compile error. - Logical
andhas higher precedence thanor, and both sit below comparisons, which is what you want for expressions likex > 0 and x < 10.
When you mix operators across categories in an ambiguous way, Zig refuses to guess and requires explicit parentheses — for example, a & b == c will not compile without them. This is intentional and aligned with the language’s “no hidden behavior” philosophy.
Key Concepts
- Explicit overflow semantics — Default
+,-,*panic on overflow in debug mode;+%/-%/*%wrap;+|/-|/*|saturate. You always know which behavior you opted into. - Signed division is a builtin, not an operator — Use
@divTrunc,@divFloor, or@divExact(and@rem/@mod) to spell out the rounding behavior for negative operands. - No operator overloading —
a + balways means primitive addition. There are no user-defined operators in Zig. ++and**are compile-time only — String concatenation and array repetition happen at compile time, with zero runtime cost.orelseis the optional-unwrap operator — It provides a default value fornulland works seamlessly with Zig’s?Toptional types.- Bitwise operators sit at the same precedence as arithmetic — Unlike C, Zig demands explicit parentheses when mixing bitwise and comparison expressions, eliminating a classic source of bugs.
- Logical
and/orshort-circuit — The right-hand operand is not evaluated when the result is already determined, just like in C and most modern languages.
Running Today
All examples can be run using Docker:
docker pull kassany/alpine-ziglang:0.14.0
Comments
Loading comments...
Leave a Comment