C Introduction

What C is, why it still matters for kernels and embedded systems, and compiling your first program with gcc.

What is C?

C is a general-purpose, compiled, statically-typed language created by Dennis Ritchie at Bell Labs between 1969 and 1973, originally to rewrite the Unix operating system in a portable, high-level language instead of assembly. It gives you close-to-the-metal control — direct pointer arithmetic, manual memory management, no hidden runtime — while still being portable across wildly different hardware.

C has been standardized by ISO/ANSI since 1989 (C89/ANSI C), with revisions including C99, C11, and C17 (a bugfix-only release) adding things like fixed-width integer types, _Bool, better Unicode support, and improved compiler diagnostics — but the core language has stayed remarkably stable for over 50 years.

Why C still matters

C is often called "the mother of languages" — C++, Java, C#, JavaScript, Go, Rust, and PHP's own engine all borrow syntax or implementation ideas from it. But C isn't just historically important — it's still the language actively chosen for:

  • Operating system kernels — Linux, most of Windows' NT kernel, and macOS's XNU kernel are written substantially in C.
  • Embedded systems — microcontrollers, IoT devices, and firmware where every byte of RAM and every CPU cycle counts, and there's often no room for a runtime or garbage collector at all.
  • Language runtimes — CPython (the reference Python implementation), the Lua interpreter, and PHP's own Zend Engine are written in C.
  • Databases and system tools — SQLite, Redis, and core Unix utilities (ls, grep, bash itself) are C.
  • Device drivers — code that talks directly to hardware needs C's predictable, minimal-abstraction memory model.

The common thread: C gives you a mental model that maps almost directly onto how the machine actually works — a skill that pays off even in higher-level languages, because understanding C makes it much easier to reason about performance, memory bugs, and what your other languages' runtimes are actually doing underneath you.

Compiling a C program

C compiles ahead of time to native machine code, via GCC's gcc or LLVM's clang on most platforms.

Bash
gcc --version
clang --version

Hello, World

C
#include <stdio.h>

int main(void) {
    printf("Hello, World!\n");
    return 0;
}
Bash
gcc -std=c17 -Wall -Wextra -o hello hello.c
./hello
Text
Hello, World!
  • #include <stdio.h> pulls in the standard I/O library, which declares printf.
  • int main(void) is the program's entry point; void here explicitly means "takes no arguments" (as opposed to empty parentheses, which in old-style C meant "unspecified arguments").
  • printf writes formatted text to standard output; \n is the newline escape sequence.
  • return 0; signals successful exit to the operating system.
  • -std=c17 selects the language standard explicitly — like C++, compilers can default to something older or to their own extensions (GNU C) unless you specify.
  • -Wall -Wextra enables a broad set of warnings. In C, where the compiler trusts the programmer more than almost any other mainstream language, these warnings are one of your main defenses against real bugs.

Common mistakes

  • Forgetting -Wall -Wextra — C will silently compile code that does something very different from what you meant (an assignment = where you meant comparison ==, for instance) unless warnings are on.
  • Not specifying -std= and being surprised when a compiler's default dialect behaves slightly differently across machines.
  • Assuming C has some runtime safety net (bounds checking, automatic memory management) that other languages provide — it deliberately doesn't; that control is the whole point.

Interview questions

Q: Why is C still relevant when higher-level languages exist? Because operating system kernels, embedded firmware, and language runtimes need predictable, minimal-overhead control over memory and hardware with no hidden runtime cost — C provides exactly that, and it remains the practical baseline that most other languages' own runtimes are implemented in.

Q: What does it mean that C "trusts the programmer"? The language performs very few runtime safety checks by default — no automatic bounds checking on arrays, no garbage collector, no null-safety enforcement. This gives the programmer maximum control and minimal overhead, but it also means many classes of bugs (buffer overflows, use-after-free) that other languages prevent automatically are the programmer's sole responsibility to avoid in C.