Consider the following Zig program:
Run it with zig run overflow.zig
:
500 * 500
is only 250,000
- so what happened? In Zig, the multiplication operator invokes Peer Type Resolution on its operands. In this case, the operands are both u16
, so a 16-bit multiply will be performed, resulting in a value of 250000
, which is larger than the maximum u16
value of 65535
- thus integer overflow occurs, which causes a panic in safety-checked build modes.
So how do we deal with this? There are least 3 ways, and it depends on what you're trying to do:
1. Use wrapping arithmetic with the *%
operator (one mnemonic for remembering it is that this combines multiply (*
) with modulus (%
):
This will perform wrapping 16-bit arithmetic, and then coerce the result to 32 bits. In this case, 500*500
produces a 16-bit result of 1101000010010000
which is then extended to the 32-bit result 00000000000000001101000010010000
, or 53392
. Note that there is no way to tell if overflow occurred, since we explicitly asked for wrapping arithmetic.
2. Use @mulWithOverflow
This will perform a 16-bit multiply. If there is no overflow, it will return false
and store the result in z
. If there is an overflow, it will return true
and store the overflowed bits in z
. Output: Oops! we had an overflow: 53392
.
3. Cast an operand to u32
:
Casting an operand to u32
will cause Peer Type Resolution to resolve both arguments to u32
, and produce a final result value of 250000
Reach out to learn more about Lager's hardware test automation platform.
Try One Month Free
hello@lagerdata.com