C: That Old Grandfather Who Just Might Beat Father Time

Adam Collins
FullStackHacks
Published in
5 min readMay 9, 2017

The C programming language is one of the oldest languages that is still widely used today. It’s history closely intertwines with the Unix Operating System. Unix development began in the mid 60s. Initial development was performed by two men named Dennis Ritchie and Ken Thompson. The original version of Unix was written in assembly language for the PDP-7. Assembly language is the lowest level programming language. Assembly has a whole host of problems that make it difficult to large applications in. One major problem with assembly is it’s unique for each processor architecture. It also involves meticulously writing code that maps out even the finest aspects of a program’s execution. Assembly language is often a headache to write and difficult to share. It doesn’t lend itself well to being read by humans making it collaborative work all the more difficult. Over the years programmers have developed higher level languages to solve these problems. High level languages will abstract out some of the programs execution with a human friendly syntax making it easier to work collaboratively and write maintainable code.

In the early 1970s Ritchie and Thompson decided they wanted to port Unix over from the PDP-7 to the PDP-11. This was a difficult task and to make it easier they wanted to complete it using a high level language. At first they started trying to re-write the OS in a programming language called B. B was a simplified version of BCPL created by Thompson. However, their were major flaws in B design. Mainly, B was an interpreter not a compiler. An interpreter is a program that runs on a machine and interprets the code at run-time. While a compiler is a piece of software that compiles a program down to machine code for the machine it will be run on. Compilers reduce the amount of computation needed to run a program, meaning compiled program typically run more efficiently. Compilers can also be more easily optimized for each machine and take advantage of their various architectures. Since B was not a compiled language it couldn’t support any of the PDP-11’s new features. Due to these shortcomings B was ruled out.

With B ruled out Ritchie made the decision to develop a new language. The new language would be called C (the letter after B). Naming wasn’t Ritchie’s strong suit… With C Ritchie added different data sizes, such as int and char, something that is common place in languages today. Ritchie made sure to develop C as a compiled language to avoid the shortcomings of B. With the C compiler engineers could finally write portable, and optimized code. Portable meaning C code can run on a variety of machines. In order to port C code over to a new machine all an engineer has to do was write a C compiler. Once the C compiler is written you then have access to any program written in C. C also made it easy to write efficient code. Despite being a high level language C code runs at a fairly low level. Being a lower level language the final output of compiled assembly code is predictable allowing engineers to write code that is “close to the metal.” Meaning, C code can be hyper efficient and have direct access to memory, which vital for certain applications.

Ritchie designed C as a procedural imperative programming language. Procedural languages are languages built as a series of one or more procedures. Procedures are often referred to as functions or subroutines. Not to be confused with functional programming which usually adds a set of restrictions such as immutability.

Imperative programming focuses on how a program should accomplish a task. It is counter to declarative. In declarative programming a program focuses on what instead how a program should accomplish its task. A good example of declarative programming is React. In React components can be written such that you simply pass in arguments and then how the component is styled/layout is abstracted away.

Being an imperative language C abstracts as little as possible. C includes static typing, but it is weakly enforced. Everything is handled by writing functions, but all functions are pass by value, as opposed to pass by reference. Pass by reference is simulated in C by passing the pointer values. By not abstracting all these little things C programs can be super efficient, but this comes at a cost. C can be a difficult language to code in. C programming requires engineers to do their own memory management. Opposed to many other languages that include garbage collectors. For example, whenever a new struct or array is declared, in C, the programmer has to allocate that space in memory and then make sure to reallocate that space once their done. If memory isn’t reallocated it is possible to have memory leaks in C; where the executing program uses up more and more memory as it runs until it crashes or greatly slows down execution.

Despite being an aging language C still sits 2nd on the TIOBE index. TIOBE index is an index that compiles a multitude of metrics to measure a programming languages popularity. The reason C is still so popular, despite it’s inherent difficulty is that it’s everywhere. The C compiler is a small compiler, and this makes it easy to write for a new architecture, so C compilers exist for every device imaginable. Under the rare case that it doesn’t exist it can be written with relative ease. C++ is often seen as a better alternative to C as it adds a lot of language features that make writing code easier. The problem with C++ is that the compiler is much more complicated and the compiled program is often twice the size of a compiled C program. For these reasons C is especially popular with embedded devices which can use uncommon architectures and have limited system resources. A lot of obscure things you wouldn’t think of like your coffee maker, or microwave likely run on C code.

C is also vital for a lot of high performance applications. Things like databases and web servers such as NGINX are written in C. These types of programs need to squeeze every ounce of performance they can which requires writing code at a low level and the only way practically do that is to use a language like C or C++. A lot of operating systems are written in C. A good portion of the Windows kernel is written in C. A lot of Linux is written with C. It’s the same story with macOS. C allows to developers to write code that is as close as possible to assembly without actually being assembly. Hence, it’s popularity with operating systems that need to run at the lowest level.

One of C’s biggest impacts has been on syntax. There is a large family of C inspired programming languages. The C-family of programming languages are like the romance languages of programming. Some of the popular C-inspired languages are Java, JavaScript, PHP, C++, C#, Perl, and Swift; all of which are in the top 10 of the TIOBE index.

Long story short C isn’t going anywhere anytime soon. It’s everywhere and is the go to language for embedded devices. No other programming language has the same level of portability and performance. C is a small abstraction above assembly code, making it perfect for certain use cases that require low level code. C has had arguably more impact than any other programming language and despite the fact that it’s an aging dinosaur it’s not going to disappear anytime soon.

Interesting links

--

--