What Is C?
What C is and why it is still everywhere: its origin at Bell Labs next to Unix, the ISO standards from C89 to C23, where C runs today and what it leaves to the programmer.
What C is
C is a
general-purpose programming language designed for writing system
software: operating systems, device firmware and the libraries other
programs are built on. It is a
high-level language
in the strict sense (you write total = total + kwh, not
processor instructions), but it sits very close to the hardware. A
few properties shape how it feels:
- Compiled. A compiler translates the source code in advance into machine code for one processor and operating system. The result is a stand-alone executable; no interpreter or virtual machine is needed to run it. See Compiling and Running C.
-
Statically typed. Every variable has a fixed type
that the compiler knows (see
static typing in C). The types are close to the machine: an
intis a fixed number of bytes, not an unlimited number. - Small. The language itself has few keywords and no classes, no exceptions, no built-in string type and no garbage collector. Most of what a program does comes from functions: its own and those of the C standard library.
- Direct memory access. Through pointers a program can work with memory addresses itself. That makes C the language of drivers and firmware, and the source of a whole family of bugs.
Here is a complete C program. It works out the average of some daily meter readings, stored as whole watt-hours:
/* Daily electricity use of one Kestrel Energy household, in watt-hours */
#include <stdio.h>
int main(void)
{
int readings[] = {11200, 9800, 12500, 10100, 13400};
int days = sizeof readings / sizeof readings[0];
long total = 0;
for (int i = 0; i < days; i++) {
total = total + readings[i];
}
printf("Days measured: %d\n", days);
printf("Average per day: %.1f kWh\n", total / 1000.0 / days);
return 0;
}
Days measured: 5 Average per day: 11.4 kWh
#include <stdio.h> makes the standard input and
output functions known, among them printf, which prints
formatted text: %d is replaced by a whole number,
%.1f by a decimal number with one digit after the
point. Every program starts in the function main; its
return 0 tells the operating system that all went well.
Blocks use curly braces, statements end with a semicolon, and
comments sit between /* and */ (or after
//). The array has no length property:
sizeof readings / sizeof readings[0] divides the size
of the whole array in bytes by the size of one element.
Before a C program runs, the compiler must accept it. A forgotten semicolon stops the build; this program never starts:
#include <stdio.h>
int main(void)
{
int kwh = 350
printf("%d kWh\n", kwh);
return 0;
}
example.c:6:5: error: expected ‘,’ or ‘;’ before ‘printf’
The message names the file, line and column
(example.c:6:5). Note that it points at the line
after the missing semicolon: the compiler only notices that
something is missing when it meets printf. Reading
compiler messages is a skill of its own; the next page has more of
them.
A short history
C grew up together with Unix. At Bell Labs, Ken Thompson and Dennis Ritchie were writing the first versions of the Unix operating system in assembly language and in a small language called B, which in turn came from BCPL. Ritchie added types to B and turned it into C. In his own account, C "came into being in the years 1969-1973, in parallel with the early development of the Unix operating system"; the most creative period was 1972. In 1973 the Unix kernel itself was rewritten in C, which made it one of the first operating systems not written in assembly language, and much easier to move to other computers.
In 1978 Brian Kernighan and Dennis Ritchie published the book The C Programming Language. For a decade, the book was the definition of the language; the C it describes is called K&R C, after its authors' initials. Compilers differed in the details, so the American National Standards Institute (ANSI) set up a committee, X3J11, to write a formal standard. Its result, ANSI X3.159-1989, is known as ANSI C or C89. ISO adopted the same text in 1990 as ISO/IEC 9899:1990 (C90), and the second edition of the book (1988) already followed the ANSI draft. Many people still say "ANSI C" when they mean "standard C".
The C standards
Since 1990 the ISO C standard, ISO/IEC 9899, defines the language and its standard library: what every keyword means, which headers and functions a compiler must offer, and which things are deliberately left to the compiler. Each new edition replaces the previous one and gets a short name after its year. The standard is maintained by WG14, the working group for C of the ISO/IEC joint committee on programming languages (ISO/IEC JTC 1/SC 22/WG14). It publishes its drafts and discussion papers openly on open-std.org; the final standard is sold by ISO.
| Name | Document | What it brought (selection) |
|---|---|---|
| K&R C | The book, 1978 | The language as Unix used it |
| C89 / C90 | ANSI X3.159-1989, ISO/IEC 9899:1990 |
The first standard: function prototypes, void,
const, the standard library
|
| C95 | ISO/IEC 9899:1990/Amd 1:1995 | An amendment, mainly for wide characters |
| C99 | ISO/IEC 9899:1999 |
// comments,
<stdint.h> (fixed-size integers),
_Bool (bool via
<stdbool.h>), declarations anywhere
(for (int i = 0; …))
|
| C11 | ISO/IEC 9899:2011 |
_Generic, _Static_assert, optional
threads; the unsafe gets function removed
|
| C17 (also C18) | ISO/IEC 9899:2018 | Corrections only, no new features |
| C23 | ISO/IEC 9899:2024 |
nullptr, constexpr,
typeof, #embed,
bool and true as keywords, binary
literals, digit separators, checked integer arithmetic
|
| C2y | Working draft | The next edition, in progress; no date yet |
C23 is the current standard, adopted by ISO and IEC in 2024; note that its document carries the year of publication (2024), while its name keeps the year the committee finished it (2023), just as C17 is ISO/IEC 9899:2018. What C23 changes is covered in Modern C and Where C Is Used.
A compiler tells your program which standard it compiles for through
the predefined macro __STDC_VERSION__: a year and month
as a number. The examples on these pages are compiled as C17:
#include <stdio.h>
int main(void)
{
printf("__STDC_VERSION__ = %ldL\n", __STDC_VERSION__);
return 0;
}
__STDC_VERSION__ = 201710L
The same program compiled as C23 (here with Clang, because the GCC version on the test machine predates most of C23) prints the C23 value:
#include <stdio.h>
int main(void)
{
printf("__STDC_VERSION__ = %ldL\n", __STDC_VERSION__);
return 0;
}
__STDC_VERSION__ = 202311L
C99 gives 199901L and C11 201112L. Code
can test the value with #if to use a newer feature only
when it exists (see
The Preprocessor and Build Tools).
Where C sits
Most software you use rests on layers of C, even when it is written in something else. A Python script runs on the CPython interpreter, which is written in C; the interpreter calls the C library; the C library makes system calls into a kernel written in C; and the devices around it, from a disk controller to a smart-meter dongle, run firmware that is very often C too.
That is why operations people meet C without writing it. When a service crashes with "Segmentation fault" and leaves a core dump, the code that crashed is usually C or C++. When a security advisory warns about a "buffer overflow" or "use after free", it is about C or C++ code. And when a server is patched for a flaw in OpenSSL or glibc, those are C libraries.
What C leaves to you
C was designed to be fast on the small computers of the 1970s and to let programmers do anything the hardware can do. The price is that the language trusts the programmer. Where Python, Java or C# check things while the program runs, C usually does not:
- No bounds checks. Reading element 4 of a four-element array is undefined behavior, but nothing stops it: usually the program just reads whatever is in memory next to the array.
-
Manual memory management. Memory requested with
mallocmust be returned withfree, at the right moment and exactly once (see manual memory management and Dynamic Memory). - Fixed-size numbers. Integer types have a fixed size and can overflow (see Variables, Types and Integers).
- No exceptions. Functions report failure through their return value, and nothing forces you to look at it (see Error Handling).
-
Strings are bytes. A string is an array of
charthat ends with a zero byte; its length is not stored anywhere.
The string point is easy to see. The serial number of a Kestrel Home P1 dongle has 11 characters, but the array that holds it needs 12 bytes, because C adds the terminating zero:
#include <stdio.h>
int main(void)
{
char serial[] = "KHP1-000231";
printf("%s has %zu characters\n", serial, sizeof serial - 1);
printf("but the array takes %zu bytes\n", sizeof serial);
printf("the last byte is %d\n", serial[11]);
return 0;
}
KHP1-000231 has 11 characters but the array takes 12 bytes the last byte is 0
And the missing bounds check: this program reads one element past the end of an array. Compiled normally, it prints whatever value happens to lie in memory there, and exits as if all went well. The examples here are built with AddressSanitizer, a checking tool built into GCC and Clang, which stops the program at the bad read and names the line:
#include <stdio.h>
int main(void)
{
int readings[4] = {120, 95, 130, 110};
int day = 4; /* imagine this came from user input */
printf("Reading for day %d:\n", day);
printf("%d\n", readings[day]); /* there is no readings[4] */
return 0;
}
Reading for day 4: SUMMARY: AddressSanitizer: stack-buffer-overflow example.c:9 in main
Bugs like this make up a large share of the serious vulnerabilities in C and C++ software: Microsoft and the Chromium project have each reported that about 70% of their serious security bugs are memory-safety problems. Heartbleed (CVE-2014-0160), the 2014 flaw in the OpenSSL library, was a missing length check in C code that let a server read past the end of a buffer and send back memory contents, including secrets. Since 2022, security agencies such as the US NSA and CISA have advised writing new software in memory-safe languages where that is practical, and hardening and testing existing C. That advice, and the tools that catch these bugs, are the subject of Undefined Behavior and Safer C and Debugging C. None of it means C is going away: it means C code needs warnings, sanitizers, tests and reviews as a matter of routine.
Where C is used
- Operating system kernels. The Linux kernel is written in C (its documentation says it is "typically compiled with gcc under -std=gnu11", the GNU dialect of C11), and so are large parts of the Windows, macOS and BSD kernels. See The Kernel and System Calls.
- Firmware and embedded systems. C is the main language of firmware: compilers exist for every microcontroller, and vendor frameworks such as Espressif's ESP-IDF for the ESP32 are C libraries.
- Language runtimes. The standard Python interpreter (CPython) is written in C, as are the interpreters of PHP and Ruby; Python's speed-critical libraries call into C code.
- Databases and infrastructure. Databases such as SQLite and PostgreSQL, web servers such as nginx, and libraries such as OpenSSL, zlib and curl are written in C.
- The glue between languages. Almost every language can call functions written in C, so a C library is the common way to offer one piece of functionality to Python, Rust, Java and C# programs at once.
The Kestrel Home pilot is a small example of the second point. The P1 dongles in the pilot homes, ESP32-C3 devices built by an outside manufacturer and sold under Kestrel's name, run firmware written in C. Kestrel does not write that code, but it does decide when a new version goes out: the update from firmware 1.3.2 to 1.4.0 is rolled out in waves under change CHG-5012. Reading the manufacturer's release notes and fix descriptions is much easier when you know what a buffer overflow or an integer overflow looks like in C. The dongle's P1 parser and its CRC check appear on Smart Meters and the P1 Port.
C is also still among the most-searched languages: the TIOBE Index of September 2026, which measures popularity through search engines, ranked C second (10.28%), after Python. Indexes like this measure attention rather than the amount of code in use, but the trend is clear: C is not fading out.
C and its relatives
C's syntax, with curly braces, semicolons,
for (i = 0; i < n; i++) and
printf-style formatting, was copied by many later
languages. That makes C code look familiar to Java, C# or JavaScript
programmers, and can mislead them: the similarity is mostly on the
surface.
- C++ started as "C with classes" and is now a much larger, separate language. Most C code compiles as C++ with small changes, but not all; modern C++ style is very different from C.
- Java and C# took C's syntax but run on a virtual machine with garbage collection, bounds checks and exceptions (see What Is Java?).
- Rust and Zig aim at the same tasks as C: kernels, firmware and fast libraries. Rust prevents most memory bugs at compile time with its ownership rules.
When people write "C/C++" they usually mean "C or C++", which share the same kinds of memory bugs and the same compilers (GCC and Clang compile both). These pages are about C only.
Learning C and certification
The rest of this topic follows the usual order: compiling, types and
operators, control flow and functions, then pointers, arrays and
strings, memory, files and errors, the preprocessor and build tools,
and finally undefined behavior, debugging, the standard library and
modern C. Every example on these pages is a complete program that
was compiled and run on a 64-bit Linux machine (ARM64) with GCC 12
(as C17, with -Wall -Wextra -Werror), or with Clang 21
where it needs C23.
There are few C certifications. The most established come from the C++ Institute (part of the OpenEDG group). As of 2026:
- C Certified Associate Programmer (CLA), exam CLA-11-03: 40 questions in 65 minutes, 70% to pass, taken at Pearson VUE. It covers the core language: types, operators, pointers and arrays, control flow, functions, the preprocessor and simple file input and output. Pages on this site that match it carry the CLA tag.
- C Certified Professional Programmer (CLP), exam CLP-12-01: 55 questions in 65 minutes, 70% to pass, at Pearson VUE. It goes further: the evolution of C up to C11, variadic functions, low-level input and output, threads, sockets, numerics, and undefined behavior. Pages that match it carry the CLP tag.
- An entry-level exam, CLE (C Certified Entry-Level Programmer), is taken online.
No exam covers C23, build tools or debuggers, so the pages on those subjects carry no tag. They matter at work all the same.