C#
C is the operator’s language for the layer right above the hardware. The Linux kernel, every libc, every TLS implementation, every database engine, every modern interpreter (CPython, V8, Lua, Ruby, PostgreSQL) is mostly C. Nothing newer has displaced it where size, speed, predictability, and ABI stability matter together.
For the operator, C is the language for kernel modules, eBPF loaders, exploit primitives, shellcode wrappers, embedded firmware, and any tool small enough to be statically linked into a payload. Reading C is also a unit-level skill for reverse engineering: every disassembly the operator sees was emitted from a C-shaped intent.
Baseline. C11 / C17 is the working baseline; C23 features
(_BitInt, constexpr, nullptr keyword, typeof)
are called out where used. gcc and clang are
interchangeable for almost everything; -Wall -Wextra
-Wpedantic is on by default.
Default toolchain. gcc or clang, make (or
cmake for anything multi-target), valgrind and
AddressSanitizer for memory bugs, gdb or lldb for
debugging, clang-format and clang-tidy for style and
lint.
Setup#
Picking a compiler and getting the toolchain on the host.
gcc, clang, musl, glibc, make,
cmake. Picking the compiler and bootstrapping a
build.
gcc, clang, ld, ar, nm, objdump,
valgrind, ASan / UBSan, gdb,
clang-format.
Single-line C idioms: MAX / MIN, bit twiddling,
ARRAY_LEN, swap.
Language#
The spec building blocks.
//, /* */, ;, \, #. Comments,
identifiers, keywords, literals, preprocessor,
statements vs expressions.
int x;, =, const, static, extern,
register, volatile. Storage classes, scope,
linkage, lifetime.
char short int long, float double, signed
/ unsigned, size_t, ptrdiff_t, fixed-width
stdint.h types, pointers, arrays, structs, unions.
+ - * / %, == != < >, && || !,
& | ^ ~ << >>, & *, ->, sizeof,
?:, ,.
if else, for, while, do while,
switch / case, break continue return goto.
Branching, loops, jumps.
T name(params), prototypes, static, inline,
variadic (va_list), function pointers, recursion.
No classes. Pattern: struct + function pointers +
self first parameter. vtables, opaque handles,
object lifecycle.
Patterns#
The layer above the spec.
RAII via cleanup, error codes, return-buffer ownership,
opaque handles, header / source split, defensive
assert, X-macros.
errno, strerror, perror, return codes,
setjmp / longjmp, abort, assert, error
conventions.
Data Structures#
The containers the operator either builds or pulls from third parties.
Arrays, structs, linked lists, hash tables, dynamic arrays. C has no built-in containers; build or import.
qsort, bsearch, memcpy, memmove,
strstr, regex.h. The C standard catalogue.
I/O#
Talking to files, the network, the shell, and the OS.
stdio.h (fopen, fread, printf),
unistd.h (read, write), sys/mman.h,
formatting, buffers.
int main(int argc, char **argv), getopt,
getopt_long, exit, EXIT_SUCCESS, stdin /
stdout streaming.
BSD sockets (socket, bind, listen,
connect), poll / epoll / kqueue, TLS
via OpenSSL / mbedTLS.
POSIX threads (pthread_*), C11 <threads.h>,
atomics (stdatomic.h), mutexes, signals,
fork / exec.
Runtime#
The compile-link-load model and what happens between source and the binary.
Preprocessor, compile, assemble, link. Static vs
dynamic linking, ld.so, ELF, the C ABI, crt0,
__attribute__.
Ecosystem#
The standard library, POSIX, and the third-party catalog.
Stdlib: string.h, stdlib.h, stdio.h.
POSIX: unistd.h, pthread.h. Third-party:
OpenSSL, zlib, libcurl, libuv,
cJSON.
GUI: GTK, Qt (C++ wrapper). Web: libmicrohttpd.
Embedded: RIOT, Zephyr. Database: SQLite
(the canonical embedded C library).
Practice#
The disciplines that keep C from biting.
Unity, Check, CMocka, Criterion,
cmocka, fuzzing with AFL++ and libFuzzer.
End-to-end C projects, a port scanner, a kernel module, a shellcode loader, an eBPF probe.