C is a general-purpose programming language created in 1972 by Dennis Ritchie at Bell Labs, primarily so that Unix could be written in something other than Assembly Language, and secondarily so that every subsequent generation of programmers could learn what a segmentation fault feels like.
C is not a high-level language. C is not a low-level language. C is the language that exists at the exact boundary between “I am writing software” and “I am manipulating hardware registers with a veneer of syntax,” and it has occupied that boundary for over fifty years without moving in either direction, because C does not move. C was placed. It remains.
“C trusts you. That is the problem.”
— The Lizard, The Three Keyboards
The Fundamental Bargain
C offers a simple contract: you may do anything you want with memory, and in exchange, memory may do anything it wants with you.
This is not a metaphor. C provides direct pointer arithmetic, manual memory allocation, unchecked array access, and implicit type coercion. It assumes the programmer is competent, careful, and fully aware of what lies at address 0x7FFF3A20. If the programmer is none of these things — and the programmer is never all of these things — C does not intervene. C does not warn. C does not throw an exception. C executes whatever instruction it was given, including the instruction to overwrite the stack, corrupt the heap, or dereference a pointer to memory that was freed forty-seven function calls ago.
The result is called undefined behavior, which is C’s way of saying “you asked for this.”
What C Built
The question “what was written in C?” is equivalent to the question “what exists?”
- Unix (1973)
- The Linux kernel (1991–present)
- Windows kernel (substantial portions)
- Every major database engine (PostgreSQL, SQLite, MySQL)
- The Python interpreter
- The Ruby interpreter
- The PHP interpreter
- Git
- Virtually every operating system, embedded controller, network router, and spacecraft guidance computer in active service
C did not win because it was elegant. C won because it compiled to fast machine code on every platform, and because the alternative was Assembly Language, which also compiled to fast machine code on exactly one platform and required the programmer to count registers by hand.
“488 bytes. Everything included. Boot and run.”
— 488 Bytes, or Why I Am As I Am
The boy who wrote 488-byte bootblocks in assembly eventually moved to C. Not because assembly was wrong, but because C let him be wrong faster, on more platforms, with fewer registers to remember.
The Children Who Left
C’s children all share one characteristic: they were created by people who loved C and wished to never use it again.
- C++ (1985) added objects, templates, and exceptions, creating a language so complex that no human has read the entire specification and remained the same person afterward.
- Java (1995) added garbage collection and removed pointers, creating a language where memory management is handled automatically and everything else is handled by a
FactoryFactoryFactory. - Go (2007) added garbage collection, kept the simplicity, removed the templates, and was designed by people who had written enough C to know exactly which parts to keep. Go is C’s most faithful child — the one who inherited the workshop but installed guardrails.
- Rust (2010) added a borrow checker, lifetime annotations, and the guarantee that if the code compiles, it will not segfault. This guarantee costs approximately four hours per function in fighting the compiler, which Rust programmers describe as “the compiler helping you.”
Each child fixed a real problem. Each child also introduced new problems. C introduced no new problems after 1972. It simply kept the original ones, perfectly preserved, like insects in amber.
The Pointer
The pointer is C’s defining feature and C’s defining hazard. A pointer is a variable that holds a memory address. That is all it is. That is all it needs to be to cause every category of software vulnerability discovered in the last fifty years.
Buffer overflows, use-after-free, double-free, null dereference, dangling pointers, wild pointers, pointer aliasing — these are not bugs in C. These are features of C, in the sense that C deliberately provides the mechanism to do all of these things and deliberately provides no mechanism to prevent any of them.
The Rust community calls this “memory unsafety.” The C community calls it “Tuesday.”
Why C Persists
C persists for the same reason The Monolith persists: it is the thing that works, at the level where working matters most, and no amount of conference talks about memory-safe languages will change the fact that the kernel running beneath those conference talks is written in C.
C persists because it is the only language that compiles to machine code on every architecture, runs without a runtime, requires no garbage collector, and occupies a binary size measured in kilobytes. When the constraints are real — embedded systems, operating systems, spacecraft — C is not a choice. C is the only option that fits.
C persists because it is boring. And Boring Technology is the technology that runs the world while exciting technology is still configuring its build system.
Measured Characteristics
- Year created: 1972
- Keywords in the language: 32
- Built-in safety features: 0
- Percentage of operating systems written in C: ~95%
- Percentage of CVEs caused by C memory bugs: ~70%
- Languages created to replace C: 12+
- Languages that have replaced C: 0
- The compiler trusts you: yes
- You deserve that trust: no
