Use when editing or reviewing general-purpose C99 — libraries, CLI tools, system code without strong opinions on memory ownership or layout. Triggers on `.c`/`.h` files and prompts about C99 idioms, designated initializers, fixed-width types, const-correctness, malloc/free patterns, inline functions, value-oriented APIs, sanitizers, or error returns, even when the user doesn't say 'C'.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Use when editing or reviewing general-purpose C99 — libraries, CLI tools, system code without strong opinions on memory ownership or layout. Triggers on `.c`/`.h` files and prompts about C99 idioms, designated initializers, fixed-width types, const-correctness, malloc/free patterns, inline functions, value-oriented APIs, sanitizers, or error returns, even when the user doesn't say 'C'.
Value-oriented APIs - Return small results by value or in a {ok, value} result struct; reserve out-params for large or multiple results, see references/value-types.md
Strings - Borrow length-carrying views, write through bounded builders over caller memory — not strlen/strcat/strtok rescans, see references/string-views.md
Input validation - Check bounds, NULL pointers, division by zero
Readability - Small functions, clear naming, comments for non-obvious logic
Signed integer overflow is undefined behavior — even INT_MAX + 1 lets the compiler eliminate "impossible" code paths
Strict aliasing means casting int* to float* is UB unless via union or memcpy — silently miscompiled at higher optimization levels
malloc returns memory that's max-aligned; custom arenas must preserve alignment for _Bool/double/SIMD types
Designated initializers (.field = x) zero-fill unmentioned members — a missing field becomes silent zero, not a compile error
long is 32-bit on Windows and 64-bit on most 64-bit Unix targets — a struct of int/long serializes and hashes differently per platform; use <stdint.h> exact-width types for any stored or shared data
Comparing a signed int against an unsigned size_t converts the int — a negative value becomes a huge size_t and the bounds check passes; keep counts/indices in size_t end to end
Return-by-value is for small PODs; returning a large struct just copies it — large or caller-owned results still take a pointer
-std=c99 usually still means the GNU dialect — set C_EXTENSIONS OFF for true ISO C99, then #define _XOPEN_SOURCE 700 or POSIX calls (readlink, strnlen, ssize_t) become implicit-declaration errors
-Wextra's -Wmissing-field-initializers/-Wmissing-braces fire on intentional zero-init — suppress those two, keep the rest of -Werror
A bare snprintf into a fixed buffer trips -Wformat-truncation; check its return (>= size ⇒ truncated) to handle the case and clear the warning