Overview
C programs are often said to have high execution efficiency. This article examines where that efficiency comes from.
Origins of C
BCPL
BCPL was created in 1967 by Martin Richards at Cambridge, based on CPL. The following BCPL code computes factorials:
GET "libhdr" LET start() = VALOF{ FOR i = 1 TO 5 DO writef("fact(%n) = %i4*n", i, fact(i)) RESULTIS 0 } AND fact(n) = n=0 -> 1, n*fact(n-1)
GET "libhdr" includes the standard library. LET start() = VALOF designates the first function called at program startup. Empty parentheses indicate no parameters; VALOF indicates the function returns a value.
FOR i = 1 TO 5 DO is a loop from 1 to 5. writef formats and outputs a string, replacing %n with i and %i4 with fact(i). *n indicates a newline. RESULTIS 0 is the return value reporting successful execution.
AND fact(n) defines the factorial function by receiving a parameter n and returning n! implemented as n=0 -> 1, n*fact(n-1).
When run, the program produces the following output:
fact(1) = 1 fact(2) = 2 fact(3) = 6 fact(4) = 24 fact(5) = 120
B
Ken Thompson developed B at Bell Labs based on BCPL while implementing Unix. The example below prints a non-negative number n in base b, where 2 <= b <= 10.
/* The following function will print a non-negative number, n, to the base b, where 2<=b<=10. This routine uses the fact that in the ANSCII character set, the digits 0 to 9 have sequential code values. */ printn(n,b) { extrn putchar; auto a; if(a=n/b) /* assignment, not test for equality */ printn(a, b); /* recursive */ putchar(n%b + '0'); }
C
In 1972 Dennis Ritchie at Bell Labs designed C based on B. The name comes from the next letter after B in BCPL. The following is a C implementation of the base-conversion function.
#include <stdio.h> void printn(int n, char b) { char a; if(a = n / b) { printn(a, b); } putchar(n % b + '0'); } int main(int argc, char **argv) { printn(8, 2); return 0; } /* Terminal: 1000 */
The C implementation is very similar to the B version.
Programming Language Levels
Machine language is binary code representing an instruction set. It is the only language a computer can execute directly. Machine code is efficient and fast to execute but difficult to write, error-prone, and hard to debug.
Assembly language uses mnemonic names and symbols to represent machine instructions, replacing binary opcodes with human-readable tokens. It improves readability compared with raw machine code but remains closely tied to hardware.
High-level languages are more abstracted from machine hardware and are closer to natural language and mathematical notation, making them easier to use for most tasks. Examples include Java, C, C++, C#, and Python.
Why C Is Fast
Higher-level languages provide conveniences that increase runtime overhead because the language or runtime handles many tasks for the programmer. C, by contrast, is intentionally minimalistic and gives the programmer direct control. The language favors speed over built-in safety: it does not check array bounds, it does not automatically detect memory leaks, and it does not prevent use of invalid pointers.
The C standard aims for portability, but it also allows programmers to sacrifice portability for faster execution when needed. C trusts the programmer rather than restricting actions.
Optimized machine code produced by a C compiler can be comparable to hand-written assembly in many cases, which explains much of C's efficiency.
ALLPCB