A modern "C" coding guideline
Description
There are plenty of Coding Guidelines out there in the Web, but many of them have one fundamental flaw: they are old.
They were written many years ago when C99 was very new or did not even exist yet.
C99 is reasonably seasoned now and most of the compiler vendors have adopted it, and apart from very particular
cases tere is no reason anymore to advocate against C99.
This guide lines have been heavily influenced by the following guides:
Python's Style Guide for C Code,
the JSF air vehicle C++ coding standard and
some styles in the POSIX API (especially the naming conventions).
Definitions
The key words "must", "must not", "required", "shall", "shall not",
"should", "should not", "recommended", "may", and "optional" in this
document are to be interpreted as described in
RFC 2119.
C dialect
-
The use of ISO C99 is recommended.
-
The new C99 type bool shall be used on all logic operations and the fixed-size
types like uint8_t should be used whenever a minimum size of a variable is required.
The new types do increase portability and can be easily redefined for compilers that do not support them.
-
Proprietary compiler extensions shall not be used.
-
All function declarations and definitions must use full prototypes (i.e. specify the types of all arguments).
-
C++ style // one-line comments may be used.
-
The tty1:command must compile without compiler warnings.
The warning level should be set on a reasonably strict level
(e.g. -W -Wall and possibly -pedantic with GCC).
Code Layout
-
The code must be properly indented with 4 spaces indentation.
Tab stops must not be used.
-
Lines should be kept shorter than 120 characters.
-
Lines should not end in white space.
Trailing white spaces may be deleted automatically be other editors,
and tend to lead to unnecessary diffs in a file.
-
Automatically expanded text (such as e.g. Version Control Keywords) should be kept to a minimum.
They tend to generate unnecessary conflicts when merging versions of the same file.
-
A function definition should be kept in one line if the the function accepts one parameter.
If the function accepts more than one parameter, then the function definition should be split,
with the first parameter in the same line as the function name and each one of the following parameters
on a separate line.
-
One space shall be placed between keywords like 'if', 'for', etc.
and the following left parenthesis; no spaces inside the parenthesis, braces as shown:
if (ptr != NULL) {
...
} else {
...
}
-
The statements forming the body of an if, else, for, etc.
shall always be enclosed in braces, even if the braces form an empty block.
-
The return statement should not get redundant parentheses:
return NULL; // correct
return (NULL); // incorrect
-
Function and macro calls shall not contain space pefore the opening parentesis
no spaces inside the parenthesis, no spaces before commas, one space after each comma.
e.g. foo(a, b, c).
-
Long lines should be split after commas in the outermost argument list.
Continuation lines shall be indented appropriately.
-
When breaking a long expression at a binary operator, put the operator at the end of the previous line,
e.g.:
if (type->tp_dictoffset != 0 &&
base->tp_dictoffset == 0) {
return 0;
}
-
Put blank lines around functions, structure definitions, and major sections inside functions.
-
Comments shall go before the code they describe.
-
All functions and variables should be declared static
unless they are to be part of a published interface.
-
External functions and variables must be declared in an appropriate header file.
Naming conventions
-
Identifiers shall be written in lowercase and should contain an underscore "_" between words.
-
Macros shall be written in uppercase letters to distinguish them from normal identifiers.
-
User defined types shall end with "_t", structures definitions end with "_s",
enum definitions end with "_e" and union definitions end with "_u".
Instances (variables) of the structures defined above don't have a suffix.
typedef unsigned int counter_t;
typedef struct {
int re;
int im;
} complex_t;
enum {
no_error,
err_out_of_mem,
err_not_implemented,
err_noclue
} error_e;
counter_t count;
complex_t a, b;
enum error_e enno;
Programming conventions
-
Debug versions of the code should use the assert() macro extensively.
This helps to spot programming errors when they occur.
In debug releases the program execution will halt on the wrong assertion,
allowing the programmer to inspect local variables.
-
Assertions shall not be used as error recovery.
In release versions, assertions must be compiled out completely.
-
A header file shall contain a mechanism that prevents multiple inclusions of itself.
-
Header files should include only the minimum set of .h files to compile it without warnings.
-
Strong typing is strongly recommended. Use size_t for objects that describe a length,
define your own types for particular objects.
This gives the compiler the opportunity to detect programming errors at compile time.