c
Use when writing C (C11) programs — numerical simulations, terminal UIs, small command-line utilities, code compiled to WebAssembly, or programs with no libc at all. Covers Make-based builds, unit tes
SKILL.mdskills/languages/c/SKILL.md
GitHubC
Default: C11, -std=c11 -Wall -Wextra -Wpedantic -O2, one Makefile with all, test, plots (or run) targets, only libm unless a library clearly earns its place.
Layout that stays testable
model.c / model.h pure state-update functions, no I/O
ui.c terminal or graphics front end
main.c argument parsing, wiring
test.c assertions on model.c, exits non-zero on failure
Public examples of this layout: lift-pilot, current-swimmer, gravity-well, relativity-rider, quantum-wave-hopper, field-ripple (all small C11 physics programs that run in a terminal).
Numerical code
- Pick the integrator for the physics: RK4 for smooth ODEs, symplectic (leapfrog/velocity Verlet) for orbits where energy must not drift, implicit or semi-Lagrangian schemes for stiff or fluid problems.
- Test against analytic solutions, not against previous output: e.g. a phugoid period against Lanchester's formula, a Hohmann transfer delta-v against the textbook value, tunnelling probability against the closed form. Assert a tolerance (e.g. within 0.3 %).
- Check conserved quantities (energy, momentum, probability norm) over long runs; drift reveals step-size or scheme problems.
- Keep units in names or comments (
v_mps,t_s).
Headless outputs
--snapshotprints one frame without a terminal, so tests and docs can capture it.--gif out.gifwrites a scripted run as an animation; a minimal GIF encoder is a few hundred lines and avoids dependencies.make plotswrites CSV and SVG charts from a scripted run, so the README images are reproducible.
Command-line utilities
- Parse options with
getopt_long; print usage on error and return 2. - Check every return value of
fopen,malloc,read,write; report withperror. - For programs without libc (raw syscalls), keep the syscall layer in one file and test it through the program's output.
Verification loop
- Build with zero warnings on GCC and Clang.
make testwith-fsanitize=address,undefined -gin a debug build.- Run the snapshot mode and compare with the expected output.
docker build .to prove a clean environment can build and test it.
Pitfalls
- Undefined behaviour (signed overflow, uninitialised reads, out-of-bounds) may only show up at
-O2. Sanitizers find most of it. floatvsdouble: usedoublefor simulation state;floataccumulates error quickly.%dwithsize_tand similar printf mismatches are UB; use%zu, enable-Wformat.- Terminal state: restore the terminal (raw mode, cursor, colours) on every exit path, including signals.
- ncurses needs
-lncurses(and sometimes-ltinfo) and wide-character variants for Unicode; checkpkg-configrather than hard-coding flags. - Integer division truncates toward zero;
-7 / 2 == -3.