This document describes my typographical conventions for writing C code. My C coding style is based on OpenBSD's Kernel Normal Form (KNF), which is documented at style(9). Parts of this document were blatantly copied from the OpenBSD manual.
Every name and sentence should be written in English for the code to be
understood by others. They should be written, however, in a concise,
agglutinative dialect of English. I name stuff using
except for constants, which are in
ALLCAPS_SNAKE_CASE; and type names,
which are in
Variable names. I use the following general rule for naming variables: “The wider the
scope of a variable, the more descriptive its name; the narrower the
scope of a variable, the shorter its name”.
n is a valid name for a
locally used numeric value.
n. For example,
ntabsis a good name for a variable storing the number of tab characters (if the variable is only used in a small function, or in a loop,
ntis a even better name). This prefix is incompatible with
min(a maximal/minimal integer is already discrete and quantitative).
iis a index,
na generic integer,
ua generic unsigned,
fa file (and
fpa file pointer), etc.
maxaddr, its relative should be
Wrapper names. If a function exists for the sole purpose of calling another function,
I give the caller the name of the callee prefixed by a lowercase letter.
This letter is
e if the caller handle errors for the callee. See the
Procedure names. Procedure names should reflect its side effect. Its name usually
contains a verb referring to this side effect, such as
savehist is a good name for a procedure whose side
effect is to save the history file.
Function names. Function names should reflect the thing it returns. Its name usually
contains a noun or adjective referring to the meaning of the value it
returns. For example, if it returns a integer meaning whether a size
is valid, it should be named
validsize; if it returns an pointer
to the next window, it should be named
nextwin. A getter can also
be prefixed with
get, as in
Constant names. Constants have the same naming rules as global variables, except that
they are written in
ALLCAPS_SNAKE_CASE. I prefer to use
values that are grouped semantically, and #define otherwise. Every
magic number other than
1 should be given a constant name (or
at least a comment); there are exceptions, such as
16 for a
function requiring a base (such as
Type names. Types, such as new
structs, are written in
PascalCase (which is
camelCase, but with the first letter capitalized).
If I use
typedef to rename a structure, I do not give the
name a fancy prefix; the
struct names and
typedef names reside in
different namespaces, so they can be the same.
struct field names
follow the same rule as global variables, and they should not be
prefixed to indicate that they are fields. The following is an
example of how I DO NOT use structures.
Label names. I name a label
error, if it jumps to a error handling part of the code;
done if it jumps to a returning part of the code; and (usually)
if it jumps out of a nested loop.
Most of my comments are a single sentence long; in which case the
sentence does not begins with upper case, and does not end with a
punctuation. All comments are written between
/* … */, except
when they are temporary (see section § Grepable Code below).
Function comment. A function whose interface is not obvious can be introduced by a comment
on the line before its definition. The comment must be a verbal sentence
in imperative mode without articles before the object; for example,
save entry in history file. The sentence should never be in third
person and must not begin with the function name (for example,
savehist saves the entry in the history file is an invalid comment).
The comment before the main function should describe what the program
Variable comment. A variable whose value is not obvious can be explained by a sentence
comment in the same line of its definition. There should not be other
variables in the same definition of a commented variable. The comment
must be a verbless sentence in dictionary form without articles; for
path to history file. Comments for boolean flag-like
variables should begin with
Block comment. When a non-functional block of code needs a comment, I put the comment in the same line of the opening brace, after it.
Paragraph comments. When I think there is a need to write more than a single sentence to
explain something, I usually rewrite it so it's easier to understand.
But there are cases when I need a comment several sentences long. This
usually occurs on large data structures and complex functions; in which
case I write the comment INSIDE the function or structure, not above it.
Those paragraph comments begin with a
/* in a line, followed by lines
* and end with a
*/ in a final line. Paragraph
comments contain real sentences, beginning with uppercase letter and
ending with punctiation.
Modeline comment. No. I do not use modeline comments such as
/* vim:set sw=8 */ or text
folding marks. It assumes everyone else should use the editor I use.
Lint comments. I comment
FALLTHROUGH in cases that fall through if, and only if, they
contain any statement; otherwise, there is no such comment. I also use
NOTREACHED comment for unreachable code.
Code must be greapable (that is, able to be searched with grep(1)).
Grepable comments. I use
/* … */ for comments, except for temporary comments, which I use
// … for. Temporary comments are comments meant to be removed later;
they include commented out code,
XXXs. Using a special
syntax for temporary comments makes it easier to grep them and remove
them. To make temporary comments even more grepable, they occur at the
beginning of the line but after any indenteation; the
keywords occur after the double comment slashes and a space, and before
Grepable function declarations. I declare functions with its type in one line, the function name and its
parameters in the following line, and the opening brace in a third line.
This allows a grep for the function declaration (
/^foobar(/) to not
intersect with a grep for uses of the function.
Grepable function calls. I call functions with no space between the opening parenthesis and the
function name, or between the parentheses and the arguments. To
differentiate a function call from a keyword (such as
have a space after it and before a opening parenthesis.
Grepable printing routines. To be able to grep for locations where something is printed to a stream,
I do not use
putchar(3), I use only the printf family of
functions. Thus, I can grep for
f?printf and get the places where
something is printed out. Most compilers optimize
so it is not a problem.
Even when the syntax or the program do not require a block of elements to be listed in a certain order, I still sort them somehow.
Order of stuff. The file has the following general layout (except when contradicted by the following paragraphs).
#includes in the order described below.
Order of inclusions. Header files for kernel (
<sys/*.h>) and for network (
come first followed by a blank line. libc headers come next, sorted
alphabetically. Library header files come next, also sorted
alphabetically. Local header files come next between double quotes,
also sorted alphabetically. All inclusions should occur at the
beginning of the file; except for the inclusion of the configuration
config.h, usually found in suckless code), which can appear
later in the code. The alphabetical order rule for each category of
included files should be broken in the following cases:
.h), which should appear last.
Order of fields. When declaring variables in
structs, I declare pointers to a
high-level data object (such as
*next) first. The other
fields are sorted by use, then by size (largest to smallest), then by
Order of options. Options should be sorted in the
getopt(3) call and the
statement, unless parts of the
switch falls through. Numerical
arguments should be checked for accuracy.
Order of declarations. When declaring variables in functions, I declare them sorted by size (largest to smallest), then by dereference level (largest to smallest), then in alphabetical order. Multiple names per line are ok if, and only if, they are in the same semantic group (or are single-letter local variables) and the same type (there should not be a pointer and a non-pointer declared in the same line). As explained later, I do not initialize variables in the declaration.
Some of my typographical conventions have no explanation other than style. That includes indentation, spacing and brace style. Trailing whitespace is an error, and should never exist in a code of mine.
Indentation style. I indent with tabs. If a line of a function is too shifted to the
right, with several levels of indentation, making it hard to fit on
the screen, it's a sign that the function is too complex and should
be broken down. To ease multiple indentation levels in a switch
statement, I align the switch and its subordinate case labels in
the same column. Tabs should be used ONLY in indentation, at the
beginning of lines; in strings I use
Alignment style. While I use tabs for indentation, I use spaces for alignment. This ensures everything will line up independent of the tab size. In particular, comments are vertically aligned.
Spacing style. I use one space around binary and ternary operators (except
->), but no space after or before unary operators. Commas have a
space after them. I do not use spaces after opening brace/parenthesis
or before the closing ones. I also use one space between a statement
keyword (if, for, while, …) and the opening parenthesis. Thre is also
a space between the closing parenthesis and the opening brace. There
should be no space between the function name and the parameter/argument
list (in function prototypes, function definitions, and function calls).
Brace style. I put the opening brace of a function in the next line, and the opening brace of a statement in the same line. I put the closing brace on its own line unless continuing a statement (if-else, do-while). If any block in an if-else sequence needs braces, then all blocks should have braces as well, even single-statement blocks. I also use braces for single statement if the inner statement needs braces. I normally do not use braces in single-statement blocks, except when the block is followed by a closing brace (so we have a cascade of closing braces).
Typedef style. In general, I avoid to
struct, especially structs whose
fields are directly accessed. It obfuscate the fact that it is a
structure. I also do not use
typedef to create an alias to a type.
Blank style. I put blank lines between function definitions. In a function, I put blank lines after the block of local variable definitions and between logical blocks of code. If the function has too many logical blocks of code, it is a sign that the function is too complex and should be broken down.
Pointer style. I declare pointers with the asterisk close to the variable name, not to the type. I do not mix pointer declaration with other declarations; I also do not mix pointer declarations with different levels of dereference.
Declaration style. I declare local variables in the beginning of the function, right after its opening brace. I also put a blank line after the block of declarations. There should be 10 or less local variables (not counting the parameters) in a function. More than that is a sign that the function is too complex and should be broken down. However, I do not initialize variables in the declarations; I initialize them opportunistically at their first use.
Parentheses style. I do not use parentheses unless they are required for precedence, the statement is confusing without them, or the compiler generates a warning without them.
Comparison style. I do not use
! for tests unless it's a boolean. That is, I use
if (*p == '\0'), not
Static functions. Functions local to one source module should be static. All non-static functions are prototyped somewhere. Functions that are private to a source module (ie', functions not used elsewhere) are prototyped at the top of the first source module. Functions that are used from other files are prototyped in the relevant header file.
Static variables. Global variables not used outside translation unit should be declared static.
Returning. To avoid exiting/returning from a function in several places, I exit at the end of the function and use goto's to jump to the exit part of the function.
Error. I use
warn(3) family of functions to handle errors.
Exiting. I usually do not use EXIT_SUCCESS or EXIT_FAILURE. I use 1 or 0 instead.
Pointers. Pointers can help readability, refer to Notes on Programming in C, by Rob Pike.
Getopt. I use
getopt(3) (and not
arg.h) to parse options. See the section
§ Sorted code for more information on how I sort entries in
Usage. I include a
usage() function in all utilities. Usage statements
should take the same form as the synopsis in manual pages. Options
without operands come first, in alphabetical order inside a single set
of braces, followed by options with operands, in alphabetical order,
each in braces, followed by required arguments in the order they are
specified, followed by optional arguments in the order they are
I use vim to write C. It gives me two features I use the most: text folding and text highlighting.
Text folding. The opening brace alone in its own line for function definitions gives me a usefull feature I set in my editor: function bodies are folded. This allows me to visually identify and navigate between functions.
Text highlighting. I do not use rainbow highlighting with every type of keyword or identifier in a different collor. I use five different styles of highlighting, four of each are shades of gray.
#definesin dark gray.
ALLCAPS_SNAKE_CASEword as a constant, as well as literal numbers).