Spokes.wiki Search About
Tech Article T1 stable source ↗ source url
Published
Created
Updated
Also known as
N2412 · Two's complement sign representation for C2x
See also
p1236-signed-integers-twos-complement · branchless-abs · branchless-programming

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/_MAX macros 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 << E2 with signed E1: defined only when E1 is non-negative and E1 × 2^E2 fits. "Otherwise, the behavior is undefined." Left-shifting a negative number is still undefined behaviour.
  • E1 >> E2 with signed negative E1: "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.

p1236-signed-integers-twos-complement · branchless-abs · branchless-programming · bit-twiddling-hacks