Skip to content
ALB Wiki

Diff — C (programming language)

Comparing rev 2 → rev 3

{{infobox
| title = C
| image = kr-c-cover.jpg
| caption = The C Programming Language, 1st edition (1978) — the "white book" that defined a generation of programming (public domain)
| full_name = C
| designed_by = Dennis Ritchie
| developer = Bell Labs (1969–1973); ISO/IEC JTC1/SC22/WG14 (1989–present)
| appeared = 1972 (first use); 1978 (K&R publication)
| typing = Static, weak, manifest
| paradigm = Imperative, procedural, structured
| influenced_by = B, BCPL, ALGOL 68, PL/I, assembly
| influenced = C++, C#, Java, JavaScript, Go, Rust, Swift, Objective-C, PHP, Perl, Python, D, Zig — virtually every language since
| latest = C23 (ISO/IEC 9899:2024, published October 2024)
| next = C2y (in progress, latest draft N3886, May 2026)
}}
**C** is the most influential programming language ever created. Designed by **Dennis Ritchie** at **Bell Labs** between 1969 and 1973 as the implementation language for the **Unix** operating system, it occupies a position in computing that no other language has matched: nearly every operating system kernel in production — Linux, Windows, macOS, iOS, Android's lower layers, the BSDs, and most embedded firmware — is written primarily in C. Nearly every language created since 1980 either compiles to C, was implemented in C, borrows C's syntax, or defines itself in opposition to C. The semicolons, the curly braces, the `for` loops, the `if/else` blocks, the `printf` format strings — these are not features of "C-like languages." They are features of C that the rest of the world adopted.
C is fifty-four years old. It is still the second most used programming language on Earth (behind Python, depending on the index) and the first choice for any software that must talk directly to hardware. It has been standardized five times — C89, C99, C11, C17, and C23 — and the committee is already working on C2y, the next revision. The language that Ritchie built on a PDP-11 in a New Jersey office is still the language the world runs on.
The TIOBE Index, Stack Overflow surveys, and GitHub usage statistics all place C in the top five languages year after year. It ranks first or second among languages that ship products people depend on without knowing it — the firmware in their car, the kernel of their phone, the database behind their bank. C is the invisible infrastructure of modern civilization.
---
-
## Before C: the ancestry
+
# Before C: the ancestry
C did not emerge from nothing. Its family tree runs through three languages, each stripping away a layer of abstraction:
**BCPL** (1967) — Martin Richards designed BCPL (Basic Combined Programming Language) at Cambridge. It was typeless: everything was a machine word. It introduced the `//` comment (which C dropped and C99 brought back thirty years later) and the idea that a systems language should compile to efficient code and be close to the machine.
**B** (1969) — Ken Thompson, working on the first Unix on the PDP-7 at Bell Labs, needed something higher-level than assembly but leaner than the full [[FORTRAN]] compiler he tried and abandoned after one day. He wrote B, derived from BCPL and influenced by Thompson's own earlier language Bon. B was also typeless — every value was a word. It worked on the word-oriented PDP-7, but when Unix moved to the byte-oriented PDP-11, the lack of types became a critical problem. You could not express a character, a byte, or a pointer to a byte in a language where everything was a word.
**NB / early C** (1971–1972) — Ritchie began adding a type system to B. For a while the result was called "NB" (New B). The type system grew — `char`, `int`, pointers, arrays, structures — and at some point NB became C. The name is simply the next letter after B, though Ritchie noted with characteristic understatement that the naming was partly coincidence and partly sequence. The transition was not a clean break: early C retained B's operator syntax (the `++` and `--` operators, the combined assignment operators `+=`, `-=`, the ternary `?:`), its terse variable naming conventions, and its fundamental orientation toward the machine. C added types on top of B's existing vocabulary rather than designing a new language from scratch — which is why C's type system has always felt thin compared to languages designed with types as a first principle.
The result was a language that sat precisely in the gap between assembly and the "high-level" languages of the era. C gave you types, structures, functions, and a standard library — but it also gave you pointers, pointer arithmetic, bit manipulation, and the ability to cast anything to anything. This deliberate positioning — close enough to the machine to replace assembly, abstract enough to be portable — is C's defining design choice and the reason for both its success and its problems.
```quote
"C came into being in the years 1969–1973, in parallel with the early development of the Unix operating system; the most creative period occurred during 1972." — Dennis Ritchie, "The Development of the C Language," 1993
```
---
-
## The birth: Bell Labs and Unix
+
# The birth: Bell Labs and Unix
[[File:thompson-ritchie-1973.jpg|right|280px|Ken Thompson (left) and Dennis Ritchie at a PDP-11, circa 1973. Public domain.]]
The critical moment came in the summer of 1973. Thompson had tried to rewrite Unix in C the previous summer but gave up — the language lacked structures, and the generated code was not efficient enough. Over the intervening year, Ritchie added `struct`, improved the compiler's code generation, and solved enough of the remaining problems that a second attempt succeeded. By the end of 1973, the Unix kernel was written in C.
This was revolutionary. Operating systems had always been written in assembly — each one tied to its specific hardware. A kernel written in a high-level language could, in principle, be **ported** to different machines by rewriting only a small hardware-dependent layer. When Unix was ported to the Interdata 8/32 in 1978, that principle became fact. Unix — and therefore C — began spreading to every architecture that existed.
The symbiosis between C and Unix cannot be overstated. C was designed to write Unix. Unix was designed to be written in C. The Unix philosophy — small tools that compose, text as a universal interface, the file system as a namespace — shaped C's standard library. The `stdio.h` functions (`fopen`, `fread`, `fprintf`, `fclose`) are a direct reflection of Unix's file I/O model. The `main(argc, argv)` convention mirrors Unix's process model. The entire C ecosystem assumes a Unix-like environment, which is why C's influence spread exactly as far as Unix did — which is to say, everywhere.
```fact
The Unix source code license from AT&T, distributed to universities starting in 1975, was one of the most consequential licensing decisions in computing history. It put C and Unix into the hands of thousands of computer science students, who learned both simultaneously and carried them into industry. Berkeley's modifications (BSD) led to FreeBSD, OpenBSD, NetBSD, and eventually macOS and iOS. The academic Unix diaspora made C the default language of systems programming worldwide.
```
---
-
## K&R: the white book
+
# K&R: the white book
In 1978, Brian Kernighan and Dennis Ritchie published *The C Programming Language* — universally known as **K&R** or "the white book." It served as the de facto standard for C for over a decade, until ANSI standardized the language in 1989.
K&R is widely regarded as one of the best programming books ever written. Its conciseness, clarity, and trust in the reader set a standard that few technical books have matched. The famous first program:
```c
#include <stdio.h>
main()
{
    printf("hello, world\n");
}
```
— appeared on page 6 and became the universal first program in every language tutorial since. The "hello, world" tradition is K&R's most visible cultural contribution, but the book's real achievement was demonstrating that a systems language could be explained clearly in 228 pages.
K&R C had no formal standard. The book *was* the standard — what Ritchie and Kernighan said the language did, that is what the language did. Compilers that disagreed were considered wrong. This worked remarkably well for a decade, but as C spread to non-Unix platforms (MS-DOS, VMS, mainframes), the divergences accumulated. Vendors added their own extensions — `far` and `near` pointers on MS-DOS for segmented memory, `#pragma` directives for platform-specific behavior, non-standard library functions — and by the mid-1980s, the idea that "C is portable" was becoming more aspiration than fact. The need for a formal standard was obvious.
The K&R era also established the practice of the compiler as a reference implementation. When the book was ambiguous — and it sometimes was — programmers looked at what Ritchie's compiler did. The PDP-11 compiler's behavior became the de facto definition of edge cases. This practice persisted well into the ANSI era: when the standard says one thing and the compiler does another, working programmers follow the compiler. The tension between the abstract standard and concrete implementations is one of the recurring themes of C's history.
---
-
## The standards: ANSI C through C23
+
# The standards: ANSI C through C23
-
### C89 / C90 — the foundation
+
## C89 / C90 — the foundation
In 1983, ANSI formed committee X3J11 to standardize C. The result, published in 1989 as **ANSI X3.159-1989** and adopted by ISO in 1990 as **ISO/IEC 9899:1990**, was the first formal C standard. It is known interchangeably as C89 (the ANSI year) or C90 (the ISO year).
C89 codified existing practice and added genuinely new features:
| Feature | What it added |
|---|---|
| `void` | An explicit "no value" type — functions could finally declare they returned nothing |
| `enum` | Named integer constants |
| `const` | Borrowed from C++ — read-only variables |
| `volatile` | For hardware registers and signal handlers — tells the compiler not to optimize away reads |
| `signed` / `unsigned` | Explicit signedness |
| Function prototypes | Also borrowed from C++ — `int add(int a, int b);` instead of just `int add();` |
| `<stdlib.h>`, `<string.h>`, `<limits.h>` | Standard library headers organized into a coherent set |
C89 also formalized the **as-if rule** — the compiler may transform the program in any way, as long as the observable behavior is identical to the abstract machine's execution. This rule is the foundation of all modern C optimization.
```fact
C89 is still the target of some new code in 2026. The [[ALB C backend]] explicitly generates C89 — the oldest, most portable C dialect — because C89 compiles on essentially every compiler ever made, from tiny embedded toolchains to modern GCC and Clang. The deliberate choice of C89 is a feature, not a compromise.
```
-
### C99 — the modernization
+
## C99 — the modernization
Published in 1999, **C99** (ISO/IEC 9899:1999) was the first major revision in a decade. It transformed C from a 1970s language with 1989 formalization into something recognizably modern:
- **`//` comments** — brought back from BCPL via C++, after thirty years of `/* */` only
- **`long long int`** — guaranteed 64-bit integers
- **`<stdint.h>` and `<inttypes.h>`** — fixed-width integer types (`int32_t`, `uint64_t`), ending decades of "how wide is `int` on this platform?"
- **`_Bool` / `<stdbool.h>`** — a proper boolean type
- **`restrict`** — a pointer qualifier telling the compiler that no other pointer aliases this one, enabling aggressive optimization
- **Compound literals** — `(struct point){.x = 1, .y = 2}` inline
- **Designated initializers** — `.field = value` syntax for structures and arrays
- **Variable-length arrays (VLAs)** — stack-allocated arrays whose size is determined at runtime
- **Inline functions** — `inline` keyword, from C++
- **Mixed declarations and code** — variables no longer had to be declared at the top of a block (from C++)
- **`<fenv.h>`** — floating-point environment control
- **`snprintf`** — the safe version of `sprintf`, preventing buffer overflows
- **Variadic macros** — `#define LOG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)`
- **`__func__`** — automatic string containing the current function name
C99 was a genuinely good standard. Its tragedy was Microsoft: MSVC did not fully support C99 for nearly two decades, which fractured the ecosystem and forced many projects to stay on C89 for portability to Windows. This created an absurd situation where the most popular desktop operating system's primary compiler did not support a 1999 language standard well into the 2010s. The consequences ripple through the C ecosystem to this day — many widely-used libraries still target C89 or a C89/C99 hybrid because they cannot assume full C99 support.
The VLA feature, in particular, proved divisive. While conceptually useful, VLAs made stack usage unpredictable and were considered a security risk (stack overflow attacks). Linus Torvalds banned VLAs from the Linux kernel, and the kernel team spent years eliminating them from the codebase. C11 made VLAs optional, tacitly acknowledging the controversy.
-
### C11 — concurrency and safety
+
## C11 — concurrency and safety
Published in 2011, **C11** (ISO/IEC 9899:2011) addressed two major gaps:
- **`<threads.h>`** — a standard threading API (thread creation, mutexes, condition variables), finally giving C portable multithreading without requiring POSIX
- **`<stdatomic.h>`** — atomic types and operations, essential for lock-free programming
- **A thread-aware memory model** — specifying how threads interact with memory, including acquire/release semantics
- **`_Static_assert`** — compile-time assertions
- **`_Alignas` / `_Alignof`** — alignment control
- **Anonymous structures and unions** — `struct { struct { int x, y; }; };`
- **`<uchar.h>`** — Unicode character types (`char16_t`, `char32_t`)
- **`_Generic`** — type-generic selection, C's answer to function overloading: `_Generic(x, int: "int", float: "float", default: "other")`
C11 also made VLAs optional (they had been mandatory in C99 but poorly supported on some platforms), introduced bounds-checking interfaces in an optional annex (Annex K), and deprecated the `gets` function (which was finally removed).
-
### C17 — the cleanup
+
## C17 — the cleanup
Published in 2018, **C17** (ISO/IEC 9899:2018) was a "bug-fix" release. It introduced no new features — only defect resolutions and clarifications. Its primary value was establishing a clean, unambiguous baseline for the next major revision.
-
### C23 — the present
+
## C23 — the present
Published in October 2024, **C23** (ISO/IEC 9899:2024) is the current standard and the most significant revision since C99. It modernizes C's surface while preserving its character:
**Types and constants:**
- `nullptr` and `nullptr_t` — a proper null pointer constant and type
- `true`, `false`, `bool` as keywords (no longer macros from `<stdbool.h>`)
- `_BitInt(N)` — bit-precise integers of arbitrary width
- `typeof` and `typeof_unqual` — standardized `typeof` operator
- `constexpr` — compile-time constants
**Syntax:**
- `[[attribute]]` syntax — unified attributes (`[[deprecated]]`, `[[fallthrough]]`, `[[maybe_unused]]`, `[[nodiscard]]`, `[[noreturn]]`)
- `#embed` — embed binary data (files, images, firmware) directly into source as initializer data
- `#elifdef` / `#elifndef` — preprocessor shorthand
- `__has_include` — test for header availability
- `__VA_OPT__` — optional variadic macro argument handling
- Digit separator `'` in numeric literals (`1'000'000`)
- Binary literal prefix `0b` (`0b1010`)
**Library:**
- `<stdbit.h>` — bit manipulation functions
- `<stdckdint.h>` — checked integer arithmetic (`ckd_add`, `ckd_sub`, `ckd_mul`)
- `memset_explicit` — guaranteed not to be optimized away (for zeroing secrets)
- `strdup` / `strndup` — finally standardized after decades as POSIX extensions
**And already in progress: C2y**, the next revision, with the latest draft (N3886) published in May 2026.
```fact
C23's `#embed` directive solves a problem as old as C itself: including binary data in a program. Before `#embed`, the standard approach was `xxd -i` to convert a file into a C array initializer — a generated source file that could be millions of lines long. `#embed` replaces this with a single preprocessor directive that compilers can handle internally, dramatically improving compile times for programs that include firmware images, texture data, or certificate bundles.
```
---
-
## The language itself
+
# The language itself
-
### What it looks like in 2026
+
## What it looks like in 2026
Modern C, written to C23, is cleaner than most people expect:
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdbit.h>
[[nodiscard]] static int popcount_and_check(unsigned n) {
    int bits = stdc_count_ones(n);
    if (bits == 0) return -1;
    return bits;
}
int main(void) {
    constexpr unsigned magic = 0xDEAD'BEEF;
    int bits = popcount_and_check(magic);
    printf("0x%X has %d set bits\n", magic, bits);
    // C23: typeof inference
    typeof(magic) copy = magic;
    printf("Copy: 0x%X\n", copy);
    // C23: nullptr instead of NULL
    int *p = nullptr;
    if (p == nullptr) {
        printf("Pointer is null (not just zero)\n");
    }
}
```
Attributes, `constexpr`, digit separators, `nullptr`, `typeof`, `<stdbit.h>` — C23 brings genuine quality-of-life improvements while remaining recognizably C.
-
### The type system
+
## The type system
C's type system is famously minimal. Every value is ultimately a sequence of bytes. The fundamental types are:
| Type | Width (typical) | Purpose |
|---|---|---|
| `char` | 8 bits | Characters, raw bytes |
| `short` | 16 bits | Small integers |
| `int` | 32 bits | The "natural" integer |
| `long` | 32 or 64 bits | Platform-dependent (the source of endless porting bugs) |
| `long long` | 64 bits | Guaranteed 64-bit (C99) |
| `float` | 32 bits | Single-precision IEEE 754 |
| `double` | 64 bits | Double-precision IEEE 754 |
| `_Bool` / `bool` | 1 bit (stored as 1 byte) | True/false |
| `_BitInt(N)` | N bits | Arbitrary-width integers (C23) |
| `void` | 0 bits | "No value" or "any pointer" |
The fixed-width types from `<stdint.h>` — `int8_t`, `uint32_t`, `int64_t` — are what modern C code actually uses, because they remove the ambiguity of "how wide is `long` on this architecture."
-
### Pointers
+
## Pointers
Pointers are C's most powerful and most dangerous feature. A pointer is an address in memory. You can:
- Dereference it (`*p`) to read or write the value at that address
- Perform arithmetic on it (`p + 3` means "three elements past p")
- Cast it to any other pointer type — including types that are completely wrong
- Pass it to a function, which can then modify the original data
```c
void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
```
Pointers are what make C a systems language. They give the programmer direct access to memory — to hardware registers, to DMA buffers, to network packet headers, to kernel data structures. They are also what make C dangerous: a pointer to freed memory, a pointer past the end of an array, a null pointer dereference, a pointer to the wrong type — all of these compile without warning and crash (or worse, corrupt data silently) at runtime.
The entire philosophy of [[Rust_(programming_language)|Rust]] can be understood as: "What if we could have pointers, but the compiler verified they were always valid?"
-
### Undefined behavior
+
## Undefined behavior
C's most controversial feature is **undefined behavior** (UB). The standard defines certain operations as having no required behavior — the compiler may do anything, including producing apparently correct code that breaks in subtle ways.
The classic examples:
- Signed integer overflow (`INT_MAX + 1`) — undefined
- Dereferencing a null pointer — undefined
- Accessing an array out of bounds — undefined
- Using a variable before initializing it — undefined
- Modifying a value twice between sequence points — undefined
The rationale is performance: by leaving these cases undefined, the compiler can assume they never happen, enabling optimizations that would be impossible if every edge case had to be defined. A compiler that knows signed overflow cannot happen can optimize `(x + 1) > x` to `true` without checking. A compiler that knows null dereference cannot happen can eliminate null checks.
The cost is that UB is the source of a vast number of security vulnerabilities. Buffer overflows (undefined behavior) are the single most exploited bug class in the history of computing. The tension between C's performance and C's safety is the central drama of systems programming, and it has driven the creation of safer alternatives — Rust, Zig, Carbon — that try to preserve C's performance while eliminating (or at least containing) UB.
```quote
"C is a razor-sharp tool with which one can create an elegant and efficient program — or cut oneself in ways that are exquisitely difficult to diagnose." — paraphrased from numerous C practitioners
```
---
-
## Where C runs — still, in 2026
+
# Where C runs — still, in 2026
C is not declining. It occupies a different niche than it did in 1990 — it is no longer the default choice for application programming — but in its domain, it remains unchallenged:
**Operating system kernels** — Linux (30+ million lines of C), Windows kernel, macOS/iOS (XNU kernel), Android's hardware abstraction layer, the BSDs, Zephyr, FreeRTOS, every RTOS on every microcontroller. Operating system kernels are C's home territory, and while Rust is making inroads (Linux now accepts Rust drivers), the vast majority of kernel code remains and will remain C for decades.
**Embedded systems** — From the $0.03 microcontroller in a washing machine to the flight computer in a satellite, embedded software is overwhelmingly C. The reasons are practical: C compilers exist for every CPU architecture ever manufactured, the language has no hidden allocations or runtime overhead, and the generated code maps predictably to machine instructions. When you have 2KB of RAM and a 16MHz clock, you cannot afford a garbage collector, a runtime, or a virtual machine. ARM, RISC-V, MIPS, AVR, PIC, MSP430, Xtensa, SuperH — every instruction set architecture ships with a C compiler, usually as the primary development tool. The embedded world runs on C because there is literally no alternative with equivalent hardware support.
**Compilers and interpreters** — GCC, Clang/LLVM's C frontend, CPython (the reference Python implementation), the Ruby interpreter (CRuby/MRI), PHP, Perl, Lua, R — all written in C. Even compilers for languages designed to replace C are often written in C themselves, at least initially.
**Databases** — SQLite (the most widely deployed database in the world — it runs on every smartphone), PostgreSQL, MySQL, Redis — all C.
**Networking** — The Linux networking stack, OpenSSL/LibreSSL, NGINX, curl, DNS resolvers, packet processing frameworks — C dominates the layer between the application and the wire.
**The C standard library itself** — `glibc`, `musl`, `bionic` (Android), `newlib` (embedded) — these are the foundational libraries that every program on a Unix-like system links against, and they are written in C.
```fact
SQLite, written in C, is estimated to run on over 4 billion devices. It is in every iPhone, every Android phone, every Mac, every Windows 10+ machine (via Edge/Chrome), every Firefox, every major web framework's development mode, every Skype client, and most television firmware. It may be the most widely deployed software component in history — and it is 153,000 lines of C, maintained by three people, with 100% branch coverage in its test suite.
```
---
-
## C's legacy in other languages
+
# C's legacy in other languages
C's syntax, semantics, and philosophy have been replicated so thoroughly that "C-family language" is a recognized category containing most of the world's programming languages:
| Language | Year | Relationship to C |
|---|---|---|
| C++ | 1985 | "C with Classes" — superset of C with OOP, templates, RAII |
| Objective-C | 1984 | C with Smalltalk-style message passing — the language of macOS/iOS until Swift |
| Java | 1995 | C's syntax with garbage collection, a virtual machine, and no pointers — designed to be "C++ without the guns" |
| JavaScript | 1995 | C's syntax applied to a prototype-based scripting language — now the most-used language on Earth |
| C# | 2000 | Microsoft's answer to Java — C's syntax on a managed runtime |
| PHP | 1995 | C's syntax applied to server-side web scripting |
| Perl | 1987 | Heavy C influence in syntax and semantics |
| D | 2001 | Designed as "what C++ should have been" — C-compatible with a GC option |
| Go | 2009 | Ken Thompson and Rob Pike's rethinking of C for networked systems — no classes, no exceptions, garbage-collected |
| [[Rust_(programming_language)|Rust]] | 2015 | Designed to replace C in systems programming by solving memory safety at compile time |
| Swift | 2014 | Apple's replacement for Objective-C — C-influenced but memory-safe |
| Zig | 2016 | A "better C" — C interop, no hidden control flow, comptime |
The `{`, `}`, `;`, `for(;;)`, `if()`, `while()`, `return`, `int`, `void`, `printf` — these are C. Every programmer in the world knows C's syntax, whether they know C or not.
---
-
## The people
+
# The people
C's creation was shaped by a remarkably small group of people, all at Bell Labs:
**Dennis Ritchie** (1941–2011) designed and implemented C. He also co-designed Unix with Ken Thompson. He received the Turing Award in 1983 (shared with Thompson) and the National Medal of Technology in 1998. He died on October 12, 2011, just days after Steve Jobs — a coincidence that drew attention to how much of the technology that Jobs made famous ran on Ritchie's software. Ritchie's death was barely noticed outside the technical community, which many regarded as a profound injustice.
**Ken Thompson** designed the B language and the original Unix. He later co-created the Go programming language at [[Google]] — a language that is, in many ways, a rethinking of the same systems programming space that C and Unix occupied, informed by decades of hindsight.
**Brian Kernighan** co-authored *The C Programming Language* and named the language's first program. He did not design C, but his writing made it accessible to a generation of programmers. He also co-designed AWK and contributed to Unix's documentation and culture.
**Steve Johnson** wrote **PCC** (Portable C Compiler), which became the standard C compiler on most Unix systems and demonstrated that C compilers could be ported between architectures — critical evidence for C's portability promise.
---
-
## The compilers
+
# The compilers
-
### GCC
+
## GCC
The **GNU Compiler Collection**, started by Richard Stallman in 1987, became the dominant C compiler by the late 1990s and remained so for over two decades. GCC's optimization capabilities, its support for virtually every CPU architecture, and its role as the default compiler for Linux made it the de facto standard. As of 2026, GCC supports C23 substantially.
-
### Clang / LLVM
+
## Clang / LLVM
**Clang**, the C frontend for the LLVM compiler infrastructure, emerged from Apple and the University of Illinois in the late 2000s. Its advantages — dramatically faster compile times, better error messages, a modular architecture, and a permissive (non-GPL) license — made it the default compiler on macOS, iOS, FreeBSD, and Android. Many Linux distributions now offer Clang as an alternative to GCC. Clang's C23 support is extensive.
-
### MSVC
+
## MSVC
Microsoft's Visual C++ compiler historically lagged behind GCC and Clang in C standard support. MSVC's C support was frozen at C89 for nearly two decades — the company focused on C++ and considered C a secondary concern. This stance softened significantly in the 2010s, and MSVC now supports most of C11 and C17, with C23 support in progress.
-
### TCC, PCC, and others
+
## TCC, PCC, and others
**TCC** (Tiny C Compiler), written by Fabrice Bellard, compiles C so fast that it can be used as a scripting interpreter — `tcc -run hello.c` compiles and executes in a single step. **PCC** has been revived as a small, clean, standards-compliant compiler. **cproc** targets QBE. **chibicc**, by Rui Ueyama, is a deliberately educational small C compiler that can compile real C programs while remaining readable enough to serve as a teaching tool. The ecosystem of small, focused C compilers remains vibrant — a testament to the language's relative simplicity (the entire C23 grammar fits in a few pages of BNF, compared to C++'s hundreds).
The diversity of C compilers matters practically: it means C code can be compiled for any CPU architecture, any operating system, and any form factor from a smartwatch to a supercomputer. No other language in 2026 can claim compiler support as broad as C's.
---
-
## C in safety-critical and real-time systems
+
# C in safety-critical and real-time systems
C dominates safety-critical software — the code where failure means physical harm. Aviation (DO-178C), automotive (ISO 26262), medical devices (IEC 62304), nuclear power, and railway signaling all use C extensively, governed by coding standards that restrict the language to a safe subset:
**MISRA C** — the Motor Industry Software Reliability Association's guidelines, originally published in 1998, define a restricted subset of C for safety-critical automotive software. MISRA C bans or restricts dynamic memory allocation (`malloc`/`free`), recursion, `goto`, pointer arithmetic, and much of the preprocessor. The result is a subset of C that is analyzable, testable, and predictable — at the cost of expressiveness. MISRA C has been adopted far beyond automotive: medical devices, avionics, and industrial control systems all use it.
**CERT C** — the SEI CERT C Coding Standard focuses on security rather than safety, providing rules for avoiding exploitable vulnerabilities. It addresses buffer overflows, integer overflows, race conditions, and the most dangerous undefined behavior patterns.
**Static analysis** — tools like Coverity, Polyspace, PC-lint, and the Clang Static Analyzer perform automated checking of C code for common defects. The state of the art can find null pointer dereferences, buffer overflows, resource leaks, and dead code automatically — but no static analyzer can catch all bugs in C, because the language's semantics make many interesting properties undecidable.
The irony is clear: the language most used in safety-critical systems is the language least equipped to prevent bugs. The industry compensates with process, testing, and tooling — coding standards, static analysis, MC/DC coverage requirements, formal verification — precisely because the language itself provides no safety net. This is the fundamental tension that drives the adoption of memory-safe languages in safety-critical domains.
---
-
## C and C++: the relationship
+
# C and C++: the relationship
C and C++ are not the same language. C++ was designed by Bjarne Stroustrup starting in 1979 as "C with Classes," and it shares C's syntax and much of its semantics. But the languages have diverged significantly:
- C++ has templates, classes, virtual functions, exceptions, RAII, move semantics, concepts, modules, coroutines, and a standard library that includes containers, algorithms, and smart pointers
- C has none of these — and this is a feature, not a deficit
C's simplicity is its value. A C program's behavior maps predictably to machine code. The language has no hidden constructors, no implicit function calls, no template instantiation, no exception unwinding tables. This predictability is why C remains preferred for kernels, firmware, and safety-critical systems where every instruction must be accounted for.
The relationship is sometimes contentious. C++ programmers argue that C's lack of safety features is inexcusable in 2026. C programmers argue that C++'s complexity is itself a source of bugs. The Linux kernel, the most important C project in the world, explicitly prohibits C++ and always has — Linus Torvalds' opinions on C++ are well-documented and unprintable on a family wiki.
---
-
## The honest critique
+
# The honest critique
C's weaknesses are well-known and serious:
**Memory safety is the programmer's problem.** C provides no protection against buffer overflows, use-after-free, double-free, null pointer dereferences, or data races. The programmer is responsible for getting every allocation, every bounds check, and every free correct. In large codebases, this is statistically impossible — Microsoft, Google, and Apple all report that roughly 70% of their security vulnerabilities are memory safety issues in C and C++ code.
**String handling is terrible.** Null-terminated strings are a design decision from 1972 that has caused incalculable damage. `strcpy` doesn't check bounds. `gets` was so dangerous it was removed from the standard. `strcat` requires the programmer to track buffer sizes manually. Even `snprintf`, the "safe" alternative, requires the programmer to pass the correct buffer size.
**The preprocessor is a blunt instrument.** `#define`, `#include`, `#ifdef` — the C preprocessor operates on text, not on the language's syntax or type system. It enables macros that look like functions but don't respect scoping, `#include` that copies entire files textually into each translation unit (causing enormous compilation overhead), and conditional compilation that creates an exponential space of possible programs that are impossible to test exhaustively.
**Undefined behavior is a loaded gun.** The list of UB in C is enormous, and modern optimizing compilers exploit it aggressively. Code that "works" in debug mode can break silently in release mode because the optimizer removed a null check that the programmer thought was a safety net. The gap between what C programmers think their code does and what the standard says it does is the source of some of the most subtle and dangerous bugs in systems software.
**The build system is chaos.** C has no standard build system, no standard package manager, no standard dependency resolution. Projects use Make, CMake, Meson, Autotools, Ninja, or custom scripts. There is no `cargo build`, no `go build`, no `npm install`. This is C's most significant practical disadvantage compared to modern languages.
These are not theoretical concerns. They are the daily reality of C programming in 2026, and they are why languages like [[Rust_(programming_language)|Rust]] exist. But they are also why C persists: every alternative that eliminates C's dangers also eliminates some of C's capabilities. The language that lets you do anything, including shoot yourself, is also the language that lets you build anything. The trade-off is inherent, and fifty-four years of history suggest that the industry will accept the danger in exchange for the power — at least for the code that runs closest to the hardware.
```fact
Dennis Ritchie on C's philosophy: "C is quirky, flawed, and an enormous success. While accidents of history surely helped, it evidently satisfied a need for a system implementation language efficient enough to displace assembly language, yet sufficiently abstract and fluent to describe algorithms and interactions in a wide variety of environments." — from "The Development of the C Language," 1993.
```
---
-
## The future of C
+
# The future of C
C is not dying, but its role is shifting. Three trends are reshaping C's position in 2026:
**The memory safety mandate.** Governments and major corporations are now explicitly recommending against new C code in contexts where memory-safe alternatives exist. The US National Security Agency, the White House Office of the National Cyber Director, CISA, and the FBI have all published guidance recommending memory-safe languages. Google, Microsoft, and Apple have all publicly committed to reducing the amount of new C (and C++) code they write. The Linux kernel's adoption of Rust is the most visible example of this trend.
**C as a compilation target.** Increasingly, C is used not as a language that humans write, but as a portable assembly language that compilers target. Languages from Haskell (GHC can target C) to Nim to Cython to the ALB C backend all compile to C, leveraging C's universal compiler support and decades of optimization infrastructure. In this role, C's readability and ergonomics don't matter — what matters is that every platform has a C compiler and that the generated code runs fast.
**C2y and beyond.** The C standards committee (WG14) continues active development. The next revision, informally called C2y, has its latest working draft (N3886) from May 2026. The committee is considering features that would have been unthinkable a decade ago — improved type inference, better generics, and further safety-oriented features. C is evolving, slowly and carefully, in the same direction the rest of the industry is moving — but on its own terms, at its own pace, preserving the backward compatibility that is its greatest strength.
The most likely future is coexistence. New safety-critical and high-performance systems will increasingly be written in Rust or other memory-safe languages. Existing C codebases — hundreds of billions of lines, representing decades of investment — will continue to run and be maintained in C. The two languages will coexist at the FFI boundary, with Rust calling C libraries and C kernels hosting Rust drivers. C will remain indispensable — not because it is the best language, but because it is the most universal, the most portable, and the most deeply embedded in the infrastructure of the world.
---
-
## C and ALB
+
# C and ALB
The [[ALB C backend]] is [[AdaLogic BASIC]]'s most complete emitter: it turns an ALB program into C89 source code, which then compiles on essentially any platform with any compiler. The deliberate targeting of C89 — the oldest, most portable dialect — reflects C's unique position as the universal compilation target. Where newer languages debate which standard to require, C89 remains the one dialect that every C compiler in existence can handle.
The ALB project includes C in its download distribution and uses C as the proof that "write once, compile anywhere" is achievable — exactly the same promise that Ritchie and Thompson demonstrated when they ported Unix to the Interdata 8/32 in 1978.
---
-
## See also
+
# See also
- [[ALB C backend]] — AdaLogic BASIC's C89 emitter
- [[Rust_(programming_language)|Rust]] — the language designed to prevent C's memory safety problems
- [[FORTRAN]] · [[COBOL]] · [[LISP]] · [[ALGOL]] — C's contemporaries and predecessors
- [[History of Programming]] — C's place in the arc
- [[AdaLogic BASIC]]
-
## References
+
# References
[1] D. M. Ritchie, "The Development of the C Language," HOPL-II: Proceedings of the Second ACM SIGPLAN Conference on History of Programming Languages, Cambridge, MA, April 1993. Also: cs.bell-labs.com/who/dmr/chist.html.
[2] B. W. Kernighan and D. M. Ritchie, *The C Programming Language*, Prentice-Hall, 1978. Second edition, 1988.
[3] ISO/IEC 9899:2024, "Information technology — Programming languages — C" (C23), published October 2024. Freely available draft: N3220 (February 2024).
[4] ISO/IEC 9899:1999, "Programming languages — C" (C99). ISO/IEC 9899:2011 (C11). ISO/IEC 9899:2018 (C17).
[5] cppreference.com, "History of C," en.cppreference.com/c/language/history.
[6] WG14 project status, open-std.org/JTC1/SC22/WG14/www/projects.html.
[7] Nokia Bell Labs, "The Creation of the UNIX Operating System," nokia.com/bell-labs/unix-history.
[8] "C23 (C standard revision)," Wikipedia. Accessed October 2026.
[[Category:Languages]]
[[Category:Programming]]