Ten small C programs that go wrong at the edge of the integer range, each stepped through one ARM instruction at a time with the registers drawn as bits before and after and the N Z C V flags shown. Everything is at 8 bits with int8_t and uint8_t so every bit is on screen; the 32-bit equivalents are named where they differ.
The loop that never ends. An unsigned countdown: 0 − 1 is 255, and 255 ≥ 0.
127 + 1. The largest signed value plus one becomes −128, with V set and C clear.
200 into an
int8_t. No arithmetic, only a narrowing store: the bits stay 0xC8 and now read as −56.−(−128). Negating the most negative value gives it back, with V set. The
abs()trap.Parsing −128. A parser that accumulates positively and negates at the end, and the one input whose positive form never fitted.
Detecting a wrap in C. C cannot read the carry flag, so the idiom
d > aasks a question only a wrap can answer yes.%dand%u. One register printed under both readings; nothing is computed, the format chooses what the top bit is worth.INT_MIN / −1. The one division that overflows: ARM’s SDIV hands back the same pattern, x86’s IDIV raises an exception.The check that vanished.
if (x + 1 > x)compiled with optimisation contains no add and no compare; the compiler assumed the undefined case away.-fwrapvbrings it back.255 + 1, and detecting it. The carry out of the top bit, and the
s < aidiom that reveals it from C.
Read it any time after From Adding to Subtracting, whose collapsed “In C” notes these scenarios expand.