This document describes C code style used by Tilen MAJERLE in his projects and libraries.
Table of Contents
- The single most important rule
- Recommended C style and coding rules
- General rules
- Comments
- Functions
- Variables
- Structures, enumerations, typedefs
- Compound statements
- Macros and preprocessor directives
- Documentation
- Header/source files
- Artistic Style configuration
- Eclipse formatter
The single most important rule
Let’s start with the quote from GNOME developer site.
The single most important rule when writing code is this: check the surrounding code and try to imitate it.
As a maintainer it is dismaying to receive a patch that is obviously in a different coding style to the surrounding code. This is disrespectful, like someone tromping into a spotlessly-clean house with muddy shoes.
So, whatever this document recommends, if there is already written code and you are patching it, keep its current style consistent even if it is not your favorite style.
General rules
Here are listed most obvious and important general rules. Please check them carefully before you continue with other chapters.
Use
C99
standardDo not use tabs, use spaces instead
Use
4
spaces per indent levelUse
1
space between keyword and opening bracketDo not use space between function name and opening bracket
1
2int32_t a = sum(4, 3); /* OK */
int32_t a = sum (4, 3); /* Wrong */Never use
__
or_
prefix for variables/functions/macros/types. This is reserved for C language itself- Prefer
prv_
name prefix for strictly module-private functions
- Prefer
Use only lowercase characters for variables/functions/macros/types with optional underscore
_
charOpening curly bracket is always at the same line as keyword (
for
,while
,do
,switch
,if
, …)1
2
3
4
5
6
7
8size_t i;
for (i = 0; i < 5; ++i) { /* OK */
}
for (i = 0; i < 5; ++i){ /* Wrong */
}
for (i = 0; i < 5; ++i) /* Wrong */
{
}Use single space before and after comparison and assignment operators
1
2
3
4
5
6int32_t a;
a = 3 + 4; /* OK */
for (a = 0; a < 5; ++a) /* OK */
a=3+4; /* Wrong */
a = 3+4; /* Wrong */
for (a=0;a<5;++a) /* Wrong */Use single space after every comma
1
2func_name(5, 4); /* OK */
func_name(4,3); /* Wrong */Do not initialize
static
andglobal
variables to0
(orNULL
), let compiler do it for you1
2
3
4
5
6
7
8
9static int32_t a; /* OK */
static int32_t b = 4; /* OK */
static int32_t a = 0; /* Wrong */
void
my_func(void) {
static int32_t* ptr;/* OK */
static char abc = 0;/* Wrong */
}Declare all local variables of the same type in the same line
1
2
3
4
5
6void
my_func(void) {
char a; /* OK */
char a, b; /* OK */
char b; /* Wrong, variable with char type already exists */
}Declare local variables in order
- Custom structures and enumerations
- Integer types, wider unsigned type first
- Single/Double floating point
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18int
my_func(void) {
/* 1 */
my_struct_t my; /* First custom structures */
my_struct_ptr_t* p; /* Pointers too */
/* 2 */
uint32_t a;
int32_t b;
uint16_t c;
int16_t g;
char h;
/* ... */
/* 3 */
double d;
float f;
}
Always declare local variables at the beginning of the block, before first executable statement
Declare counter variables in
for
loop1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/* OK */
for (size_t i = 0; i < 10; ++i)
/* OK, if you need counter variable later */
size_t i;
for (i = 0; i < 10; ++i) {
if (...) {
break;
}
}
if (i == 10) {
}
/* Wrong */
size_t i;
for (i = 0; i < 10; ++i) ...Avoid variable assignment with function call in declaration, except for single variables
1
2
3
4
5
6
7
8
9
10
11
12void
a(void) {
/* Avoid function calls when declaring variable */
int32_t a, b = sum(1, 2);
/* Use this */
int32_t a, b;
b = sum(1, 2);
/* This is ok */
uint8_t a = 3, b = 4;
}Except
char
,float
ordouble
, always use types declared instdint.h
library, eg.uint8_t
forunsigned 8-bit
, etc.Do not use
stdbool.h
library. Use1
or0
fortrue
orfalse
respectively1
2
3
4
5
6
7/* OK */
uint8_t status;
status = 0;
/* Wrong */
bool status = true;Never compare against
true
, eg.if (check_func() == 1)
, useif (check_func()) { ... }
Always compare pointers against
NULL
value1
2
3
4
5
6
7
8
9
10
11
12
13void* ptr;
/* ... */
/* OK, compare against NULL */
if (ptr == NULL || ptr != NULL) {
}
/* Wrong */
if (ptr || !ptr) {
}Always use pre-increment (and decrement respectively) instead of post-increment (and decrement respectively)
1
2
3
4
5
6
7int32_t a = 0;
...
a++; /* Wrong */
++a; /* OK */
for (size_t j = 0; j < 10; ++j) {} /* OK */Always use
size_t
for length or size variablesAlways use
const
for pointer if function should not modify memory pointed to bypointer
Always use
const
for function parameter or variable, if it should not be modified1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* When d could be modified, data pointed to by d could not be modified */
void
my_func(const void* d) {
}
/* When d and data pointed to by d both could not be modified */
void
my_func(const void* const d) {
}
/* Not required, it is advised */
void
my_func(const size_t len) {
}
/* When d should not be modified inside function, only data pointed to by d could be modified */
void
my_func(void* const d) {
}When function may accept pointer of any type, always use
void *
, do not useuint8_t *
- Function must take care of proper casting in implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/*
* To send data, function should not modify memory pointed to by `data` variable
* thus `const` keyword is important
*
* To send generic data (or to write them to file)
* any type may be passed for data,
* thus use `void *`
*/
/* OK example */
void
send_data(const void* data, size_t len) { /* OK */
/* Do not cast `void *` or `const void *` */
const uint8_t* d = data;/* Function handles proper type for internal usage */
}
void
send_data(const void* data, int len) { /* Wrong, not not use int */
}
- Function must take care of proper casting in implementation
Always use brackets with
sizeof
operatorNever use Variable Length Array (VLA). Use dynamic memory allocation instead with standard C
malloc
andfree
functions or if library/project provides custom memory allocation, use its implementation- Take a look at LwMEM, custom memory management library
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/* OK */
void
my_func(size_t size) {
int32_t* arr;
arr = malloc(sizeof(*arr) * n); /* OK, Allocate memory */
arr = malloc(sizeof *arr * n); /* Wrong, brackets for sizeof operator are missing */
if (arr == NULL) {
/* FAIL, no memory */
}
free(arr); /* Free memory after usage */
}
/* Wrong */
void
my_func(size_t size) {
int32_t arr[size]; /* Wrong, do not use VLA */
}
- Take a look at LwMEM, custom memory management library
Always compare variable against zero, except if it is treated as
boolean
typeNever compare
boolean-treated
variables against zero or one. Use NOT (!
) instead1
2
3
4
5
6
7
8
9
10size_t length = 5; /* Counter variable */
uint8_t is_ok = 0; /* Boolean-treated variable */
if (length) /* Wrong, length is not treated as boolean */
if (length > 0) /* OK, length is treated as counter variable containing multi values, not only 0 or 1 */
if (length == 0) /* OK, length is treated as counter variable containing multi values, not only 0 or 1 */
if (is_ok) /* OK, variable is treated as boolean */
if (!is_ok) /* OK, -||- */
if (is_ok == 1) /* Wrong, never compare boolean variable against 1! */
if (is_ok == 0) /* Wrong, use ! for negative check */Always use
/* comment */
for comments, even for single-line commentAlways include check for
C++
withextern
keyword in header fileEvery function must include doxygen-enabled comment, even if function is
static
Use English names/text for functions, variables, comments
Use lowercase characters for variables
Use underscore if variable contains multiple names, eg.
force_redraw
. Do not useforceRedraw
Never cast function returning
void *
, eg.uint8_t* ptr = (uint8_t *)func_returning_void_ptr();
asvoid *
is safely promoted to any other pointer type- Use
uint8_t* ptr = func_returning_void_ptr();
instead
- Use
Always use
<
and>
for C Standard Library include files, eg.#include <stdlib.h>
Always use
""
for custom libraries, eg.#include "my_library.h"
When casting to pointer type, always align asterisk to type, eg.
uint8_t* t = (uint8_t*)var_width_diff_type
Always respect code style already used in project or library
Comments
Comments starting with
//
are not allowed. Always use/* comment */
, even for single-line comment1
2//This is comment (wrong)
/* This is comment (ok) */For multi-line comments use
space+asterisk
for every line1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/*
* This is multi-line comments,
* written in 2 lines (ok)
*/
/**
* Wrong, use double-asterisk only for doxygen documentation
*/
/*
* Single line comment without space before asterisk (wrong)
*/
/*
* Single line comment in multi-line configuration (wrong)
*/
/* Single line comment (ok) */Use
12
indents (12 * 4
spaces) offset when commenting. If statement is larger than12
indents, make comment4-spaces
aligned (examples below) to next available indent1
2
3
4
5
6
7void
my_func(void) {
char a, b;
a = call_func_returning_char_a(a); /* This is comment with 12*4 spaces indent from beginning of line */
b = call_func_returning_char_a_but_func_name_is_very_long(a); /* This is comment, aligned to 4-spaces indent */
}
Functions
Every function which may have access from outside its module, must include function prototype (or declaration)
Function name must be lowercase, optionally separated with underscore
_
character1
2
3
4
5
6
7/* OK */
void my_func(void);
void myfunc(void);
/* Wrong */
void MYFunc(void);
void myFunc();When function returns pointer, align asterisk to return type
1
2
3
4
5
6
7/* OK */
const char* my_func(void);
my_struct_t* my_func(int32_t a, int32_t b);
/* Wrong */
const char *my_func(void);
my_struct_t * my_func(void);Align all function prototypes (with the same/similar functionality) for better readability
1
2
3
4
5
6
7
8/* OK, function names aligned */
void set(int32_t a);
my_type_t get(void);
my_ptr_t* get_ptr(void);
/* Wrong */
void set(int32_t a);
const char * get(void);Function implementation must include return type and optional other keywords in separate line
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/* OK */
int32_t
foo(void) {
return 0;
}
/* OK */
static const char*
get_string(void) {
return "Hello world!\r\n";
}
/* Wrong */
int32_t foo(void) {
return 0;
}When function returns pointer, asterisk character must be aligned to return type (
char*
)1
2
3
4
5
6
7
8
9
10
11/* OK */
const char*
foo(void) {
return "test";
}
/* Wrong */
const char*
foo(void) {
return "test";
}
Variables
Make variable name all lowercase with optional underscore
_
character1
2
3
4
5
6
7
8
9/* OK */
int32_t a;
int32_t my_var;
int32_t myvar;
/* Wrong */
int32_t A;
int32_t myVar;
int32_t MYVar;Group local variables together by
type
1
2
3
4
5
6void
foo(void) {
int32_t a, b; /* OK */
char a;
char b; /* Wrong, char type already exists */
}Do not declare variable after first executable statement
1
2
3
4
5
6void
foo(void) {
int32_t a;
a = bar();
int32_t b; /* Wrong, there is already executable statement */
}You may declare new variables inside next indent level
1
2
3
4
5
6
7int32_t a, b;
a = foo();
if (a) {
int32_t c, d; /* OK, c and d are in if-statement scope */
c = foo();
int32_t e; /* Wrong, there was already executable statement inside block */
}Declare pointer variables with asterisk aligned to type
1
2
3
4
5
6/* OK */
char* a;
/* Wrong */
char *a;
char * a;When declaring multiple pointer variables, you may declare them with asterisk aligned to variable name
1
2/* OK */
char *p, *n;
Structures, enumerations, typedefs
- Structure or enumeration name must be lowercase with optional underscore
_
character between words - Structure or enumeration may contain
typedef
keyword - All structure members must be lowercase
- All enumeration members must be uppercase
- Structure/enumeration must follow doxygen documentation syntax
When structure is declared, it may use one of 3
different options:
- When structure is declared with name only, it must not contain
_t
suffix after its name.1
2
3
4struct struct_name {
char* a;
char b;
}; - When structure is declared with typedef only, it has to contain
_t
suffix after its name.1
2
3
4typedef struct {
char* a;
char b;
} struct_name_t; - When structure is declared with name and typedef, it must not contain
_t
for basic name and it has to contain_t
suffix after its name for typedef part.1
2
3
4
5typedef struct struct_name {
char* a;
char b;
char c;
} struct_name_t;
Examples of bad declarations and their suggested corrections
1 | /* a and b must be separated to 2 lines */ |
When initializing structure on declaration, use
C99
initialization style1
2
3
4
5
6
7
8/* OK */
a_t a = {
.a = 4,
.b = 5,
};
/* Wrong */
a_t a = {1, 2};When new typedef is introduced for function handles, use
_fn
suffix1
2
3/* Function accepts 2 parameters and returns uint8_t */
/* Name of typedef has `_fn` suffix */
typedef uint8_t (*my_func_typedef_fn)(uint8_t p1, const char* p2);
Compound statements
Every compound statement must include opening and closing curly bracket, even if it includes only
1
nested statementEvery compound statement must include single indent; when nesting statements, include
1
indent size for each nest1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/* OK */
if (c) {
do_a();
} else {
do_b();
}
/* Wrong */
if (c)
do_a();
else
do_b();
/* Wrong */
if (c) do_a();
else do_b();In case of
if
orif-else-if
statement,else
must be in the same line as closing bracket of first statement1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25/* OK */
if (a) {
} else if (b) {
} else {
}
/* Wrong */
if (a) {
}
else {
}
/* Wrong */
if (a) {
}
else
{
}In case of
do-while
statement,while
part must be in the same line as closing bracket ofdo
part1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/* OK */
do {
int32_t a;
a = do_a();
do_b(a);
} while (check());
/* Wrong */
do
{
/* ... */
} while (check());
/* Wrong */
do {
/* ... */
}
while (check());Indentation is required for every opening bracket
1
2
3
4
5
6
7
8if (a) {
do_a();
} else {
do_b();
if (c) {
do_c();
}
}Never do compound statement without curly bracket, even in case of single statement. Examples below show bad practices
1
2
3
4if (a) do_b();
else do_c();
if (a) do_a(); else do_b();Empty
while
,do-while
orfor
loops must include brackets1
2
3
4
5
6
7
8/* OK */
while (is_register_bit_set()) {}
/* Wrong */
while (is_register_bit_set());
while (is_register_bit_set()) { }
while (is_register_bit_set()) {
}If
while
(orfor
,do-while
, etc) is empty (it can be the case in embedded programming), use empty single-line brackets1
2
3
4
5
6
7
8
9
10/* Wait for bit to be set in embedded hardware unit
uint32_t* addr = HW_PERIPH_REGISTER_ADDR;
/* Wait bit 13 to be ready */
while (*addr & (1 << 13)) {} /* OK, empty loop contains no spaces inside curly brackets */
while (*addr & (1 << 13)) { } /* Wrong */
while (*addr & (1 << 13)) { /* Wrong */
}
while (*addr & (1 << 13)); /* Wrong, curly brackets are missing. Can lead to compiler warnings or unintentional bugs */Always prefer using loops in this order:
for
,do-while
,while
Avoid incrementing variables inside loop block if possible, see examples
1 | /* Not recommended */ |
Switch statement
Add single indent for every
case
statementUse additional single indent for
break
statement in eachcase
ordefault
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36/* OK, every case has single indent */
/* OK, every break has additional indent */
switch (check()) {
case 0:
do_a();
break;
case 1:
do_b();
break;
default:
break;
}
/* Wrong, case indent missing */
switch (check()) {
case 0:
do_a();
break;
case 1:
do_b();
break;
default:
break;
}
/* Wrong */
switch (check()) {
case 0:
do_a();
break; /* Wrong, break must have indent as it is under case */
case 1:
do_b(); /* Wrong, indent under case is missing */
break;
default:
break;
}Always include
default
statement1
2
3
4
5
6
7
8
9
10
11
12
13
14/* OK */
switch (var) {
case 0:
do_job();
break;
default: break;
}
/* Wrong, default is missing */
switch (var) {
case 0:
do_job();
break;
}If local variables are required, use curly brackets and put
break
statement inside.- Put opening curly bracket in the same line as
case
statement1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23switch (a) {
/* OK */
case 0: {
int32_t a, b;
char c;
a = 5;
/* ... */
break;
}
/* Wrong */
case 1:
{
int32_t a;
break;
}
/* Wrong, break shall be inside */
case 2: {
int32_t a;
}
break;
}
- Put opening curly bracket in the same line as
Macros and preprocessor directives
Always use macros instead of literal constants, specially for numbers
All macros must be fully uppercase, with optional underscore
_
character, except if they are clearly marked as function which may be in the future replaced with regular function syntax1
2
3
4
5/* OK */
/* Wrong */Always protect input parameters with parentheses
1
2
3
4
5/* OK */
/* Wrong */Always protect final macro evaluation with parenthesis
1
2
3
4
5
6
7
8
9
10
11/* Wrong */
/* Imagine result of this equation using wrong SUM implementation */
int32_t x = 5 * SUM(3, 4); /* Expected result is 5 * 7 = 35 */
int32_t x = 5 * (3) + (4); /* It is evaluated to this, final result = 19 which is not what we expect */
/* Correct implementation */When macro uses multiple statements, protect it using
do-while (0)
statement1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68typedef struct {
int32_t px, py;
} point_t;
point_t p; /* Define new point */
/* Wrong implementation */
/* Define macro to set point */
SET_POINT(&p, 3, 4); /* Set point to position 3, 4. This evaluates to... */
(&p)->px = (3); (&p)->py = (4); /* ... to this. In this example this is not a problem. */
/* Consider this ugly code, however it is valid by C standard (not recommended) */
if (a) /* If a is true */
if (b) /* If b is true */
SET_POINT(&p, 3, 4);/* Set point to x = 3, y = 4 */
else
SET_POINT(&p, 5, 6);/* Set point to x = 5, y = 6 */
/* Evaluates to code below. Do you see the problem? */
if (a)
if (b)
(&p)->px = (3); (&p)->py = (4);
else
(&p)->px = (5); (&p)->py = (6);
/* Or if we rewrite it a little */
if (a)
if (b)
(&p)->px = (3);
(&p)->py = (4);
else
(&p)->px = (5);
(&p)->py = (6);
/*
* Ask yourself a question: To which `if` statement `else` keyword belongs?
*
* Based on first part of code, answer is straight-forward. To inner `if` statement when we check `b` condition
* Actual answer: Compilation error as `else` belongs nowhere
*/
/* Better and correct implementation of macro */
/* Or even better */
(p)->px = (x); \
(p)->py = (y); \
} while (0) /* 2 statements. No semicolon after while loop */
/* Now original code evaluates to */
if (a)
if (b)
do { (&p)->px = (3); (&p)->py = (4); } while (0);
else
do { (&p)->px = (5); (&p)->py = (6); } while (0);
/* Every part of `if` or `else` contains only `1` inner statement (do-while), hence this is valid evaluation */
/* To make code perfect, use brackets for every if-ifelse-else statements */
if (a) { /* If a is true */
if (b) { /* If b is true */
SET_POINT(&p, 3, 4);/* Set point to x = 3, y = 4 */
} else {
SET_POINT(&p, 5, 6);/* Set point to x = 5, y = 6 */
}
}Always write macro documentation as regular function with additional
hideinitializer
doxygen keyword1
Avoid using
#ifdef
or#ifndef
. Usedefined()
or!defined()
instead1
2
3
/* do something */Always document
if/elif/else/endif
statements1
2
3
4
5
6
7
8
9
10
11
12
13/* OK */
/* Do if XYZ defined */
/* Do if XYZ not defined */
/* Wrong */
/* Do if XYZ defined */
/* Do if XYZ not defined */Do not indent sub statements inside
#if
statement1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/* OK */
/* do when ABC defined */
/* Do when XYZ not defined */
/* Wrong */
/* do when ABC defined */
/* Do when XYZ not defined */
Documentation
Documented code allows doxygen to parse and general html/pdf/latex output, thus it is very important to do it properly.
Use doxygen-enabled documentation style for
variables
,functions
andstructures/enumerations
Always use
\
for doxygen, do not use@
Always use
5x4
spaces (5
tabs) offset from beginning of line for text1
2
3
4
5
6/**
* \brief Holds pointer to first entry in linked list
* Beginning of this text is 5 tabs (20 spaces) from beginning of line
*/
static
type_t* list;Every structure/enumeration member must include documentation
Use
12x4 spaces
offset for beginning of comment1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* \brief This is point struct
* \note This structure is used to calculate all point
* related stuff
*/
typedef struct {
int32_t x; /*!< Point X coordinate */
int32_t y; /*!< Point Y coordinate */
int32_t size; /*!< Point size.
Since comment is very big,
you may go to next line */
} point_t;
/**
* \brief Point color enumeration
*/
typedef enum {
COLOR_RED, /*!< Red color. This comment has 12x4
spaces offset from beginning of line */
COLOR_GREEN, /*!< Green color */
COLOR_BLUE, /*!< Blue color */
} point_color_t;Documentation for functions must be written in function implementation (source file usually)
Function must include
brief
and all parameters documentationEvery parameter must be noted if it is
in
orout
for input and output respectivelyFunction must include
return
parameter if it returns something. This does not apply forvoid
functionsFunction can include other doxygen keywords, such as
note
orwarning
Use colon
:
between parameter name and its description1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* \brief Sum `2` numbers
* \param[in] a: First number
* \param[in] b: Second number
* \return Sum of input values
*/
int32_t
sum(int32_t a, int32_t b) {
return a + b;
}
/**
* \brief Sum `2` numbers and write it to pointer
* \note This function does not return value, it stores it to pointer instead
* \param[in] a: First number
* \param[in] b: Second number
* \param[out] result: Output variable used to save result
*/
void
void_sum(int32_t a, int32_t b, int32_t* result) {
*result = a + b;
}If function returns member of enumeration, use
ref
keyword to specify which one1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/**
* \brief My enumeration
*/
typedef enum {
MY_ERR, /*!< Error value */
MY_OK /*!< OK value */
} my_enum_t;
/**
* \brief Check some value
* \return \ref MY_OK on success, member of \ref my_enum_t otherwise
*/
my_enum_t
check_value(void) {
return MY_OK;
}Use notation (`NULL` =>
NULL
) for constants or numbers1
2
3
4
5
6
7
8
9/**
* \brief Get data from input array
* \param[in] in: Input data
* \return Pointer to output data on success, `NULL` otherwise
*/
const void *
get_data(const void* in) {
return in;
}Documentation for macros must include
hideinitializer
doxygen command1
2
3
4
5
6
7
8/**
* \brief Get minimal value between `x` and `y`
* \param[in] x: First value
* \param[in] y: Second value
* \return Minimal value between `x` and `y`
* \hideinitializer
*/
Header/source files
Leave single empty line at the end of file
Every file must include doxygen annotation for
file
andbrief
description followed by empty line (when using doxygen)1
2
3
4
5/**
* \file template.h
* \brief Template include file
*/
/* Here is empty line */Every file (header or source) must include license (opening comment includes single asterisk as this must be ignored by doxygen)
Use the same license as already used by project/library
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32/**
* \file template.h
* \brief Template include file
*/
/*
* Copyright (c) year FirstName LASTNAME
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* This file is part of library_name.
*
* Author: FirstName LASTNAME <optional_email@example.com>
*/Header file must include guard
#ifndef
Header file must include
C++
checkInclude external header files outside
C++
checkInclude external header files with STL C files first followed by application custom files
Header file must include only every other header file in order to compile correctly, but not more (.c should include the rest if required)
Header file must only expose module public variables/types/functions
Use
extern
for global module variables in header file, define them in source file later1
2
3
4
5
6
7
8
9/* file.h ... */
#ifndef ...
extern int32_t my_variable; /* This is global variable declaration in header */
#endif
/* file.c ... */
int32_t my_variable; /* Actually defined in source */Never include
.c
files in another.c
file.c
file should first include corresponding.h
file, later others, unless otherwise explicitly necessaryDo not include module private declarations in header file
Header file example (no license for sake of an example)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/* License comes here */
/* Include headers */
extern "C" {
/* File content here */
}
Artistic style configuration
AStyle is a great piece of software that can
help with formatting the code based on input configuration.
This repository contains astyle-code-format.cfg
file which can be used with AStyle
software.
1 | astyle --options="astyle-code-format.cfg" "input_path/*.c,*.h" "input_path2/*.c,*.h" |
Eclipse formatter
Repository contains eclipse-ext-kr-format.xml
file that can be used with
eclipse-based toolchains to set formatter options.
It is based on K&R formatter with modifications to respect above rules.
You can import it within eclipse settings, Preferences -> LANGUAGE -> Code Style -> Formatter
tab.