C — Advanced
Reason about C the way the compiler does: the abstract machine and undefined behavior, object representation and ABI, allocators and ownership, linking, forensic debugging, POSIX processes, pthreads and the C11 memory model, loopback sockets, I/O and performance engineering, security hardening — capped by a systems capstone verified two-sided against a real gcc.
Who this course is for
Learners who finished C — Intermediate (or are fluent in pointers, structs, dynamic memory, multi-file builds, and hand-built data structures) and want to build, debug, optimize, secure, and reason about systems-level C.
What you will be able to do
- Predict what the C abstract machine guarantees and where undefined behavior begins
- Reason about object representation, alignment, padding, and ABI-stable struct layout
- Design allocators, arenas, and ownership contracts with explicit lifetimes
- Exploit and defend against optimizer assumptions around UB and aliasing
- Read ELF objects, symbols, and relocations; diagnose real linker failures
- Engineer builds with Make flags, warning discipline, and reproducible targets
- Debug crashes from core evidence: exit codes, signal names, heap invariants
- Program POSIX processes and pipes, and pthreads with mutexes, condvars, barriers
- Apply the C11 memory model: seq_cst, acquire/release, relaxed, and CAS loops
- Implement TCP/UDP services over loopback with framing and error contracts
- Tune I/O with buffering, writev, and mmap; measure before optimizing
- Harden C against overflows, format-string and parsing bugs; port code across platforms
The C Object Model
What a C object is at the byte level: representations, alignment, padding, and the behavior classes (unspecified, implementation-defined, undefined) that everything later in this course depends on.
The C Abstract Machine
The invisible machine your C code describes: objects, lvalues, sequencing, side effects, and observable behavior — the model the optimizer is allowed to break.
Advanced Pointer Semantics
Arithmetic beyond the bounds rule, aliasing and restrict, and pointer-built interfaces — the semantics the compiler actually assumes.
Undefined Behavior and the Optimizer
The UB catalog that matters, how optimization exploits its absence, and the discipline of making UB detectable instead of assumed.
Memory Allocators from First Principles
Build the allocators production systems actually use — arenas, pools, growth policies — and learn the tradeoffs each one makes.
Ownership and Error-Safe Cleanup
C has no garbage collector — it has contracts. Ownership documentation, transfer vs borrow, and cleanup ladders that survive every error path.
Advanced Data Structures in C
Open-addressed hash tables, binary heaps, and union-find — implemented with explicit memory layout and measured complexity.
Generic Programming in C
void* interfaces, callback dispatch, _Generic selection, and macro metaprogramming — the real C toolbox, with its limits stated honestly.
The Preprocessor and Compile-Time Techniques
Expansion mechanics, variadic macros, static assertions, and feature detection — the metaprogramming layer that runs before the compiler does.
The Compilation Pipeline
Source to binary through four real stages — preprocess, compile, assemble, link — executed with actual toolchain commands inside the sandbox.
Object Files, ELF, and the Linker
Sections, symbol tables, and relocation — inspecting real binaries with nm and objdump, and driving the linker by hand.
ABI and Binary Compatibility
Calling conventions, struct layout, and the stable-interface contract — why two separately compiled files agree, and when they stop.
Reading What the Compiler Emits
Compiler-generated assembly as evidence: prologues, register discipline, and watching optimization transform real functions — arch-aware, never arch-worshipping.
Build Engineering: Make, Flags, and Warnings
Make dependency graphs, incremental builds, and the warning-and-hardening flags that turn the toolchain into a static analyzer — practiced on real builds inside the sandbox.
Debugging Forensics Without a Debugger
No gdb in the graded sandbox — so this module teaches the durable skill: invariants that fail loudly, minimal repro, and assertion discipline that survives every environment.
Sanitizers: Concepts and Detection Without Them
What ASan/UBSan/TSan actually detect, why they belong in every CI — and, because this sandbox ships none of them, how to find the same defect classes by disciplined reasoning.
POSIX Processes: fork, exec, wait
Everything above ISO C is labeled as such: fork/exec/wait are POSIX. This module builds the process machinery every shell and server relies on — with the real calls, in the real sandbox.
Concurrency Deep: Locks, Conditions, Barriers
Mutexes, condition variables, and barriers: what each costs, how they fail, and the discipline that keeps threaded programs correct and debuggable.
The C11 Memory Model: Atomics and Ordering
The C11 memory model: sequenced consistency, acquire and release, relaxed atomics, and the CAS loop — why ordering is part of the algorithm.
Loopback Sockets: TCP, UDP, Framing
Sockets against 127.0.0.1 in the sandbox: connection lifecycle, byte-stream framing, timeouts, and UDP datagrams. POSIX/BSD sockets — never part of ISO C; labeled as such.
High-Performance I/O: Buffers, writev, mmap
Buffered vs raw I/O, writev, and mmap: what each saves, what each costs, and how to measure instead of guessing where time goes.
Performance Tuning: Layout, Locality, Measurement
The performance thinking that survives contact with reality: data layout decides cache behavior, and measurement decides everything else.
Security Engineering: Bounds, Formats, Hardening
The memory-corruption families (overflow, format strings, TOCTOU, use-after-free) from the defender's seat: what breaks, how to detect it, how to prevent it. Prevention and detection only.
Portability and the Systems Capstone
What the standard leaves to the implementation, how to detect it at compile time and run time, and the final integration project that uses every module before it.