C code style
This skill applies whenever you are writing, editing, or reviewing .c or .h
files in a project that adopts this style guide. The full rule set lives in
CODING_RULES.md at the repository root — that
file is the single source of truth (this repository's README.md is just a
symlink to it, so it renders on the GitHub front page). This skill exists to
make the rules operational: what to self-apply while writing code, and how to
run the formatter afterward.
1. Read the rules first
Before writing or editing C code, read CODING_RULES.md in this repository
(or wherever this skill was installed alongside it — if it's not there, the
checklist in step 3 below is a self-contained fallback). Do not rely on
memory of "typical" C style — several of this guide's rules are deliberately
non-default (e.g. (void) on zero-parameter functions, at most 2 return
points per function, no stdbool.h).
2. What clang-format fixes for you
Don't hand-format these — write reasonably and let the formatter normalize them in step 4: indentation and spacing, brace placement, pointer-asterisk alignment, function-prototype alignment, trailing commas in struct initializers, blank-line and parenthesis spacing.
3. What clang-format will NOT fix — apply these yourself while writing
These are semantic or naming rules; a formatter cannot infer them. Apply them as you write, not after:
- Names (variables, parameters, struct/enum members) are lowercase with
underscores and at least 3 characters. Never a bare
__/_prefix.staticmodule-private functions use aprv_prefix. - Use
stdint.htypes (uint8_t,int32_t, ...) exceptchar/float/double. Avoidstdbool.h; use1/0. - Don't rely on static initializers for
global/staticvariables that need a real startup value in embedded contexts — give the module aninit()function instead. - Declare all locals at the top of a block, grouped by type, in order: custom structs/enums (and their pointers) → integers (widest unsigned first) → floating point.
const-correct pointers and parameters; generic pointers arevoid*, cast internally, never cast avoid*return value.- Every function with zero parameters uses
(void), never empty(). - A function has at most 2
returnpoints: one early return for parameter/argument validation, one at the end. Noreturnin the middle — use a return-value variable to accumulate the result instead. - Check a pointer against
NULLbefore dereferencing it (unless the surrounding code guarantees it can't beNULL). Afterfree(ptr), immediately setptr = NULL. - Boolean-treated variables are compared with
if (x)/if (!x), never== 1/== 0; counter/value variables use> 0/== 0, never bareif (x). - Doxygen: every function (including
staticones) gets a\brief, a\param[in]/\param[out]per parameter, and a\returnif it returns non-void. The doc block goes at the function's definition (where the body is, typically the.cfile) — never duplicated at the declaration in the header. Pad tags so description text starts at column 22 (seetemplate.c/template.hfor the exact alignment). Wrap identifiers, constants, and literals referenced in prose in backticks.
4. Format the code
After writing or editing any .c/.h file, run the formatter using this
repository's .clang-format (it's found automatically by walking up from the
file's directory — no path needed):
scripts/check-format.sh <changed-file.c> [<changed-file.h> ...]
This script:
- Checks
clang-formatis onPATHand is version20or newer (this repo's minimum — seeCODING_RULES.md, General rules). - If missing or too old, prints the install command for the current OS
(
brew install llvmon macOS, distro package or LLVM apt repo on Linux, the LLVM installer on Windows) and exits non-zero — install it, then re-run. - Otherwise runs
clang-format -ion the given files.
To verify compliance without writing changes (e.g. before reporting a task
done), use --check instead:
scripts/check-format.sh --check <file.c> [<file.h> ...]
Exits 0 if already compliant, non-zero (with the specific violations) if
not.
5. Verified behavior
This flow was tested directly in this repository: check-format.sh correctly
refuses to run when clang-format is absent (prints the right install
command per OS and exits 1), and — once clang-format is installed —
correctly detects a deliberately mis-formatted file with --check, fixes it
with the default (in-place) mode, and re-verifies clean afterward.
template.c and template.h in this repository both pass --check as-is —
use them as a reference for exact formatting and doxygen alignment.