C's Flexible Integer Sizes Were Not a Design Mistake
C's Flexible Integer Sizes Were Not a Design Mistake
The Core Thesis:
intwas never intended to be a synonym for "32 bits." Instead, C's adaptable integer types were the primary mechanism for achieving portability across a fragmented landscape of 12, 18, 36, and 60-bit architectures.
The Beginner's Hurdle
At our school, we specialize in retro hardware and vintage game consoles. Consequently, we often guide developers who are just starting their journey with the C programming language. Many of these students transition from high-level languages such as:
- Python
- JavaScript
- Java
- C#
- Swift
It doesn't take long for these newcomers to realize that the assumptions they held in their primary languages are guaranteed do not apply in C. A frequent point of confusion is the fundamental question: "Exactly how many bits does this variable occupy in memory?"
The sizeof Revelation
A pivotal moment for any C student is mastering the sizeof operator. On a modern machine, seeing the following output is standard:
printf("%zu", sizeof(int));
// Output: 4

However, I often share my own experience: when I first learned to code on an old 386 machine, the result was different:
printf("%zu", sizeof(int));
// Output: 2

This leads to a critical realization: native C integer types have no fixed size. Types like char, int, short, and long provide no absolute guarantee regarding their byte count.
Solving the Ambiguity with STDINT.H
Because most professional software requires predictable memory layouts, we advise students to use the <stdint.h> header. Introduced in the C99 standard (1999), this header allows developers to specify exact widths regardless of the target architecture:
| Type | Description |
|---|---|
int8_t | Signed integer |
uint8_t | Unsigned integer |
int16_t | Signed integer |
uint16_t | Unsigned integer |
int32_t | Signed integer |
uint32_t | Unsigned integer |
Defending a 1970s Design in a 2020s World
There is a common narrative in modern programming circles—often echoed on social media—that these platform-dependent types were a "design mistake."

The argument is simple: int varies between 16 and 32 bits; long is 64 bits on Linux but 32 bits on 64-bit Windows. This inconsistency has fueled decades of portability bugs. But judging a 1970s decision by 2020s standards is anachronistic.
C was designed as a portable systems language meant to map efficiently to wildly different hardware. Its "portability" wasn't the Java-style "write once, run anywhere," but rather "write once, compile efficiently anywhere."
The Chaotic Hardware Landscape of the 60s and 70s
Today, we assume a world of 8-bit bytes, byte-addressable memory, and two's-complement arithmetic. In the early days, none of this was standard.
Historical Machine Word Sizes
| Machine | Word Size | Notable Characteristics |
|---|---|---|
| DEC PDP-8 | 12 bits | Extremely popular minicomputer |
| DEC PDP-7 | 18 bits | The birthplace of UNIX (Assembly) |
| DEC PDP-11 | 16 bits | Byte-addressed; the environment where C matured |
| DEC PDP-10 | 36 bits | Characters often packed in 7 or 9-bit groups |
| Honeywell 6000 | 36 bits | 9-bit characters; an early C target |
| UNIVAC 1100 | 36 bits | Ones'-complement arithmetic; still has C compilers |
| IBM 7090 | 36 bits | Used 6-bit character codes |
| SDS 940 / ICL 1900 | 24 bits | ICL utilized 6-bit characters |
| Burroughs B5000 | 48 bits | Tagged, stack-oriented architecture |
| CDC 6600 | 60 bits | 6-bit characters; no byte addressing |
| Cray-1 | 64 bits | Word-addressed; short, int, and long could all be 64-bit |
| DG Nova | 16 bits | Word-addressed; distinct pointer representations |
| Intel 8086 | 16 bits | Segmented memory (near/far pointers) |

The Complexity of Early Data
- Characters: Ranged from 6-bit sets and 7-bit ASCII to 9-bit bytes and IBM's EBCDIC.
- Negative Numbers: Represented via two's complement, ones' complement, or sign-magnitude.
- Addressing: Some machines only addressed whole words. In such cases, a character pointer was calculated as:
The Lineage of C
C's philosophy is a direct evolution of its predecessors.
BCPL and B were typeless. A value was simply a bit pattern; whether it was treated as an address or an integer depended entirely on the operator used. This was incredibly efficient for word-addressed machines. When C emerged on the byte-addressed PDP-11, it needed to balance this efficiency with the emerging need for types.
Summary Checklist for C Portability
- Avoid assuming
intis 32 bits. - Use
sizeofto determine memory footprints. - Use
<stdint.h>for fixed-width requirements. - Respect the target architecture's word size.
