This document describes coding conventions and formatting styles we use in Graphene. All newly commited code must conform to them to pass a review.
Note: Old code is temporarily excluded from these rules until reformatted.
To make formatting easier we've added an integration with clang-format
(currently only for C
code). You must install appropriate package from your distribution to use it. For Ubuntu 18.04 you
can setup it this way:
sudo apt-get install clang-format
Usage: (assuming you're in the project's top directory)
make format
This make
target reformats all source files in-place, so we recommend you first commit them
(or add to git index with git add -A
), reformat and then verify reformatting results using git diff
(or git diff --cached
if you
used git add
).
We use a style derived (and slightly modified) from Google C++ Styleguide.
See our .clang-format config for precise rules.
- Indentation: 4 spaces per level.
- Maximal line length: 100 characters.
- Brace placement:
void f() {
if (a && b) {
something();
}
}
if-else
formatting:
if (x == y) {
...
} else if (x > y) {
...
} else {
...
}
- Asterisks (
*
) should be placed on the left, with the type. Multiple pointer declarations in one line are disallowed. Example:
int* pointer;
int* another_pointer;
int non_pointer_a, non_pointer_b, non_pointer_c;
- Function call/declaration folding: aligned to a matching parenthesis. Required only if the one-line version would exceed the line length limit. Examples:
int many_args(int something_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
int also_looooooong,
int c);
...
many_args(some_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_calculations,
many_args(123,
also_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
789),
many_args(1, 2, 3));
if
,else
,do
,for
,while
,switch
andunion
should be followed by a space.- Includes should be grouped and then sorted lexicographically. Groups should be separated using a
single empty line.
Groups:
- Matching
.h
header for.c
files. - Standard library headers.
- Non-standard headers not included in Graphene's repository (e.g. from external dependencies,
like
curl.h
). - Graphene's headers.
- Matching
-
Variable and function names should be sane and easy to understand (example:
nofpts
is bad,points_cnt
is ok). -
All non-static function interfaces should be documented in comments (especially pointer ownerships). Same for public macros.
-
Prefer readable code and meaningful variable/function names to explaining implementation details in comments within a function. Only tricky or unintuitive code should be commented.
-
Magic numbers (e.g. buffer sizes) shouldn’t be hardcoded in the implementation. Use
#define
. -
Naming:
- Macros and global constants should be
NAMED_THIS_WAY
. - Functions, structures and variables should be
named_this_way
. - Global variables should be prefixed with
g_
(e.g.g_thread_list
).
- Macros and global constants should be
-
Types:
- All in-memory sizes and array indexes should be stored using
size_t
. - All file offsets and sizes should be stored using
uint64_t
. - In general, C99 types should be used where possible (although some code is "grandfathered" in, it should also be changed as time allows).
- All in-memory sizes and array indexes should be stored using
-
goto
may be used only for error handling. -
Yoda conditions (e.g.
if (42 == x)
) or any other similar constructions are not allowed. -
Prefer
sizeof(instance)
tosizeof(type)
, it’s less error-prone.
TODO