C is the desert island language.
This is my favourite statement from a talk Rob Pike gave in 2001. Despite its age, despite many flaws, C is still the de facto standard, the lingua franca. Why? As with other older languages, inertia is partly to blame, but this cannot be the only reason. C must possess a near-perfect balance of vital language features.
Or as Linus Torvalds puts it, “C is the only sane choice”.
One of C’s designers, Dennis Ritchie, gives a modest account of the evolution of C.
The canonical reference, Kernighan and Ritchie’s "The C Programming Language" is slim, yet contains much more than the language specification. There are only a few elementary concepts to introduce. Most of the text demonstrates the power of these concepts.
Not only is C easy for humans to understand, but machines too can pick up the language quickly. C compilers can be developed rapidly: my favourite example is this International Obfuscated C Contest entry. Perhaps no other language is so ubiquitous. I have seldom worked with a platform without a C compiler.
I can roughly envision the assembly generated by a C statement, so I can make educated guesses about time and space efficiency.
Brevity is the soul of wit. We automatically clip, shorten, abbreviate and decapitate lengthy expressions. We enjoy doing so.
In my Eiffel days, I was encouraged to write "integer", not "int", "character", not "char", and so on. I believe Java encourages this practice too. Supposedly clarity is maximized. But how can this be if we do the opposite when we speak? Do you say “taxi cab”, or “taximeter cabriolet”? Redundant utterances are tiresome and worse still, obscure the idea being expressed.
We call friends by shortened versions of their names. We should enjoy the same custom with code. Leave verbosity for license agreements. Though terseness can be taken too far, C at least lets you reach a comfortable level. As the first chapter of "The Practice of Programming" states, though clarity is not the same as brevity, clarity is often achieved through brevity.
C possesses elementary yet powerful constructs that are missing from other languages. For example, goto may be absent. Another example is the prohibition of function pointers in Pascal or Java. In the latter, one can work around this restriction by defining interfaces possessing only one function, but why introduce unnecessary barriers?
If a concept is easy to translate to assembly, then chances are C has it: pointers, function pointers, goto, arbitrary function exit points, literal arrays. These can be dangerous in the wrong hands, but they are preferable to tools that have been excessively watered down because of some ideology.
I have yet to find a language with similar ingredients in a better combination. C is mostly close enough to assembly for when speed matters, yet structured enough for large complicated projects.
Unfortunately I have very little of my own work that I can use to prove my point. However I needn’t look far. The software I use most frequently, the Linux kernel, the X server, the rxvt terminal emulator, vim editor, bash shell, GNU Coreutils, gcc compiler, git version control system, and so on, all happen to be written in C. The most notable exceptions are my web browsers, which are written in C++.
C is yet another triumph of the "worse is better" approach. By insisting on simplicity, at the cost of sweeping some distasteful details under the rug, its designers ensured its success.
C was fortunate to mature before object-oriented programming became fashionable. As a result, C is free of the burdensome baggage that accompanies an object-oriented language. However, we can still match wits with a typical object-oriented language, because in C, function pointers are easy to play with.
Lumping together function pointers that operate on the same data structure is essentially object-oriented programming, except the programmer has more control and flexibility. It would be nice to have some syntactic sugar to sweeten the common cases, but plain C is still comfortable.