WG14 N2412 — two's complement becomes the only representation in C
N2412, Two's complement sign representation for C2x (JF Bastien, Apple, and Jens Gustedt, INRIA; revision 2, 11 August 2019), is the C committee paper that removed ones' complement and sign-and-magnitude from the C standard. It went into C23 (ISO/IEC 9899:2024). Read via research pass 2026-09-28, together with the matching clauses of the C23 working draft N3220 (open-std.org/…/n3220.pdf, §6.5.8).
What the paper changes
- Signed integers are two's complement, full stop. The other two representations are deleted.
- The minimum value of an N-bit signed type is fixed at −2^(N−1). C17 had allowed the bit pattern "sign bit set, all others zero" to be a trap representation even under two's complement; that is gone.
- Signed and unsigned counterparts must have the same width, and the
_MIN/_MAXmacros are now derived from_WIDTH.
What it deliberately leaves alone
The paper says so in its introduction. C++ had just gone further (p1236-signed-integers-twos-complement): overflow and out-of-range conversion mapped to modulo arithmetic, no traps. N2412 records that "WG14 has not yet found consensus for these points, so we leave them as they are." The London 2019 meeting voted for the representation change only.
The C23 draft shows what that means for the shift operators this spoke's tricks use (N3220 §6.5.8):
E1 << E2with signedE1: defined only whenE1is non-negative andE1 × 2^E2fits. "Otherwise, the behavior is undefined." Left-shifting a negative number is still undefined behaviour.E1 >> E2with signed negativeE1: "the resulting value is implementation-defined." The arithmetic (sign-extending) right shift is still not guaranteed.- A shift count that is negative or at least the operand's width is undefined, as before.
What this settles for the spoke
Half of synthesis's portability question is now answered by the standard's text. The representation
assumption behind branchless-abs (that -x is ~x + 1) is guaranteed in C23. The shift assumption
(that x >> 31 gives all ones for negative x) is still implementation-defined in C, and C++20 is the
language where it became guaranteed. So the old caveat "portable in practice, not by the letter" is now
true of the shift and no longer true of the representation.
One more thing is unchanged. Signed overflow is undefined in both languages, so abs(INT_MIN) is undefined
whichever way it is computed.
Tier
T1. A committee paper by the proposal's authors, and the adopted standard text it produced. Both are the primary record of what the language requires.
Related
p1236-signed-integers-twos-complement · branchless-abs · branchless-programming · bit-twiddling-hacks