Naming
Variable names and static helper functions should use camelCase.
Types, enums and constants should use TitleCase.
Externally-accessible functions should have a TitleCase name with their
namespace (e.g. tito
) as an all-lowercase prefix.
Macros should use ALL_CAPS with underscores, but macros should be generally
avoided.
Names should be descriptive, with the extent of their specificity relative to
the size of their scope. Function-local variables need not specify their entire
scope in their names, whereas externally accessible functions should be clear
when used in many different contexts. With the exception of loop variables
(e.g. i
), tiny-scope variables with an obvious use (e.g. tmp
in a swap),
and namespace prefixes ubiquitous in the codebase (e.g. tito
), names should
be composed of english words, or in the case of very long names, common and
unambiguous abbreviations. We should all be able to pronounce your names.
Macros
Macros should be generally avoided in favor of enums for integer constants,
const
variables for other constants, and small functions that are likely to
be inlined for function-like macros.
Use enums for nontrivial (e.g. 0, 1, -1) integer constants instead of const
variables, macros, or literals.
Avoid using #ifdef
in functions, preferring instead to factor out the
conditional code into a small function, putting the #ifdef
around that whole
function body and providing a no-op stub in the #else
.
Always provide a comment at the #endif
with a repetition of the
condition.
#ifdef CONFIG_SOMETHING
// ...
#endif // CONFIG_SOMETHING
Blocks and Whitespace
Braces should follow the One True Brace Style: all control structures (with the
exception of individual case
s) should use braces, and opening braces should
be on the same line as their structure heading, with a space between the
heading and the brace. The exception to this is function definitions, which
should have the opening brace on its own line, indented at the same level as
the function heading. Closing braces should be on their own line, except when
followed by while
in a do loop or else
or else if
in an if structure.
Blocks should be indented 2 spaces (including the cases in a switch
), and
line continuations should be indented 4 spaces. Try not to have your lines
exceed 80 characters. However, do not break strings, especially user-visible
strings, as this makes them more difficult to search the code for.
Every statement should be followed by a newline. Having multiple statements on
a single line doesn't save that much space, and is easy to misread as a single
statement. Similarly, declare each variable in a separate declaration, as the
binding of various type modifiers in C makes multi-variable declarations easy
to misread.
All assignment operators, binary arithmetic, bitwise, and logical operators,
all comparison operators, and the ternary conditional operator should have
spaces on both sides. Use parentheses to be explicit about operation order. We
shouldn't have to look up the precedence chart to read your code. Commas should
have space after them and no space before them. Other operators should not have
whitespace between them and their operands. When breaking a line at an operator
other than the comma, the operator should start the second line.
Put a space after if
, switch
, case
, for
, do
, and while
.
Do not leave whitespace at the end of lines.
Commenting
Try to write code that does not require inline commenting, but if you need to
do something non-obvious, provide a brief comment. Inline comments should be
immediately before the code they describe, indented at the same level.
Provide a brief Doxygen comment for each function describing its purpose. Markdown formatting style is preferred. Usage examples here and in file-level comments are encouraged. If you have a file-level comment, do not list the file name, author, or other metadata. This metadata is already accessible through git.
Commenting out large blocks of code is discouraged, but if you really need to,
use #if 0
... #endif
rather than /*
... */
. It actually nests properly.
But you can really do whatever you want, because you shouldn't check in blocks
of commented-out code.
Do not include editor modelines (e.g. -*- mode: c -*-
,
vim: set filetype=c :
) in files.
The search token for todo comments is TODO:
.
Declarations
Do not use auto
, inline
, or register
. Everywhere it is reasonable to have
an auto-storage-class variable, the auto
is implicit. inline
and
register
, on the other hand, do nothing in modern compilers. Do use
noreturn
if your function unconditionally exits.
Function declarations should include the names of parameters, and should always
include the return type.
Generally avoid declaring typedefs, especially to hide pointers. The
exceptions to this are when you really do need an opaque object (which should
be rarely), and when using function pointers. Function pointer syntax is
weird, and using a typedef for them generally makes the code clearer.
Only declare global variables when you really need to.
Statements
Avoid goto
and longjmp
.
All switch
statements should have a default
label, even if it is just a
false assertion. All case
s in a switch
that have any code exclusive to them
should end with break
. This means don't get cute with fallthrough.
Use assertions liberally.
Functions
From the Linux kernel coding-style.rst:
Functions should be short and sweet, and do just one thing. They should fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24, as we all know), and do one thing and do that well.
The maximum length of a function is inversely proportional to the complexity and indentation level of that function. So, if you have a conceptually simple function that is just one long (but simple) case-statement, where you have to do lots of small things for a lot of different cases, it's OK to have a longer function.
However, if you have a complex function, and you suspect that a less-than-gifted first-year high-school student might not even understand what the function is all about, you should adhere to the maximum limits all the more closely. Use helper functions with descriptive names....
Another measure of the function is the number of local variables. They shouldn't exceed 5-10, or you're doing something wrong. Re-think the function, and split it into smaller pieces. A human brain can generally easily keep track of about 7 different things, anything more and it gets confused. You know you're brilliant, but maybe you'd like to understand what you did 2 weeks from now.
If the success or failure of a function is relevant to the caller, the function
should return a boolean success value, unless it would otherwise return some
other value in which case it should return some invalid value (e.g. NULL,
-1).
Use early return
, continue
, and break
. That is, do
static bool doSomething() {
if (!conditionTrue()) {
return false;
}
char *resource = loadResource();
return doSomethingElse(resource);
}
rather than
static bool doSomething() {
if (conditionTrue()) {
char *resource = loadResource();
return doSomethingElse(resource);
}
return false;
}
Additional Reading
The Linux kernel's 4.Coding.rst is probably a good read, even though some
of it is specific to kernel development.