From 24660f18be84d6f4753768be30aa163241115f19 Mon Sep 17 00:00:00 2001 From: kevyang Date: Tue, 24 Jul 2018 23:18:37 -0700 Subject: [PATCH] update style guide (#170) --- docs/c-styleguide.txt | 427 ------------------------------- docs/coding_style.rst | 583 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 583 insertions(+), 427 deletions(-) delete mode 100644 docs/c-styleguide.txt create mode 100644 docs/coding_style.rst diff --git a/docs/c-styleguide.txt b/docs/c-styleguide.txt deleted file mode 100644 index 69661c0d8..000000000 --- a/docs/c-styleguide.txt +++ /dev/null @@ -1,427 +0,0 @@ -- No literal tabs. Expand tabs to 4 spaces. -- Indentation is 4 spaces. -- No more than 3 levels of indentation, otherwise you should think about - refactoring your code. -- Use one statement per line. -- Make sure that your editor does not leave space at the end of the line. -- snake_case for variable, function and file names. -- Use your own judgment when naming variables and functions. Be as Spartan - as possible. Eg: Using name like this_variable_is_a_temporary_counter - will usually be frowned upon. -- Don’t use local variables or parameters that shadow global identifiers. - GCC’s ‘-Wshadow’ option can help you to detect this problem. - -- Avoid using int, char, short, long. Instead use int8_t uint8_t, int16_t, - uint16_t, int32_t, uint32_t, int64_t, uint64_t, which are available in - . However, when interfacing with system calls and libraries - you cannot get away from using int and char. -- Use bool for boolean variables. You have to include -- If memory usage or alignment is a concern, avoid using a bool as type for - struct member names. Instead use unsigned 1-bit bit field. e.g. - struct foo { - unsigned is_bar:1; - }; - However, if neither memory usage or alignment will be significantly impacted - by the struct, opt for using bool for the sake of readability. -- Always use size_t type when dealing with sizes of objects or memory ranges. -- Your code should be 64-bit and 32-bit friendly. Bear in mind problems - of printing, comparisons, and structure alignment. You have to include - to get generic format specifier macros for printing. - -- 80 column line limit. -- If you have to wrap a long statement (> 80 column), put the operator at the - end of the line and indent the next line at the same column as the arguments - in the previous column. Eg: - while (cnt < 20 && this_variable_name_is_too_long && - ep != NULL) { - z = a + really + long + statement + that + needs + three + lines + - gets + indented + on + the + same + column + as + the + - previous + column - } - - and: - - int a = function(param_a, param_b, param_c, param_d, param_e, param_f, - param_g, param_h, param_i, param_j, param_k, param_l); - -- Always use braces for all conditional blocks (if, switch, for, while, do). - This holds good even for single statement conditional blocks. Eg: - if (cond) { - stmt; - } -- Placement of braces for non-function statement blocks - put opening brace - last on the line and closing brace first. Eg: - if (x is true) { - we do y - } -- Placement of brace for functions - put the opening brace at the beginning - of the next line and closing brace first. This is useful because several - tools look for opening brace in column one to find beginning of C - functions. Eg: -int -function(int x) -{ - body of the function -} - -- Closing brace is empty on a line of its own, except in cases where it is - followed by a continuation of the same statement, i.e. a "while" in a - do-statement or an "else" in an if-statement, like this: - do { - body of do-loop - } while (condition); - - and, - - if (x == y) { - .. - } else if (x > y) { - ... - } else { - .... - } - -- Column align switch keyword and the corresponding case/default keyword. Eg: - switch (alphabet) { - case 'a': - case 'b': - printf("I am a or b\n"); - break; - - default: - break; - } - -- Forever loops are done with for, and not while. Eg: - for (;;) { - stmt; - } - -- Don't use a space after a function name. -- Do not needlessly surround the return expression with parentheses. -- Use space after keywords. Exceptions are sizeof, typeof, alignof and - __attribute__, which look like functions. -- Do not add spaces around (inside) parenthesized expressions. - s = sizeof( sizeof(*p)) ); /* bad example */ - s = sizeof(sizeof(*p)); /* good example */ -- Casts should not be followed by space. Eg: - int q = *(int *)&p -- There is no need to type cast when assigning a void pointer to a non-void - pointer, or vice versa. -- Avoid using goto statements. However there are some exceptions to this rule - when a single goto label within a function and one or more goto statements - come in handy when a function exits from multiple locations and some common - work such as cleanup has to be done. Eg: -int -fun(void) -{ - int result = 0; - char *buffer; - - buffer = malloc(1024); - if (buffer == NULL) { - return -1; - } - - if (condition1) { - while (loop1) { - ... - } - result = 1; - goto out; - } - - ... -out: - free(buffer); - return result; -} -- When declaring pointer data, use '*' adjacent to the data name and not - adjacent to the type name. Eg: - int - function(int *p) - { - char *p; - - } -- Use one space around (on each side of) most binary and ternary operators, - such as any of these: - = + - < > * / % | & ^ <= >= == != ? : - but no space after unary operators: - & * + - ~ ! sizeof typeof alignof __attribute__ defined - no space before the postfix increment & decrement unary operators: - ++ -- - and no space around the '.' and "->" structure member operators. - -- 0 and NULL; use 0 for integers, 0.0 for doubles, NULL for pointers, and - '\0' for chars. -- Test pointers against NULL. E.g, use: - if (p == NULL) - - not: - - !(p) - -- Do not use ! for tests unless it is a boolean. E.g. use: - if (*p == '\0') - - not: - - if (!*p) - -- Don't use assignments inside if or while-conditions. E.g, use: - - struct foo *foo; - foo = malloc(sizeof(*foo)); - if (foo == NULL) { - return -1 - } - - not: - - struct foo *foo; - if ((foo = malloc(sizeof(*foo))) == NULL) { - return -1; - } - -- Don't ever use typedef for structure types. Typedefs are problematic - because they do not properly hide their underlying type; for example you - need to know if the typedef is the structure itself or a pointer to the - structure. In addition they must be declared exactly once, whereas an - incomplete structure type can be mentioned as many times as necessary. - Typedefs are difficult to use in stand-alone header files: the header - that defines the typedef must be included before the header that uses it, - or by the header that uses it (which causes namespace pollution), or - there must be a back-door mechanism for obtaining the typedef. -- The only exception for using a typedef is when you are defining a type - for a function pointer or a type for an enum. Eg: - - typedef void (*foo_handler_t)(int, void *); - - or: - - typedef enum types { - TYPE_1, - TYPE_2 - } types_t; - -- Use just one variable declaration per line when variables are part of a - struct. This leaves you room for a small comment on each item, explaining - its use. Declarations should also be aligned. Eg, use: - - struct foo { - int *foo_a; /* comment for foo_a */ - int foo_b; /* comment for foo_b */ - unsigned foo_c:1; /* comment for foo_c */ - }; - - and not: - - struct foo { - int *foo_a, foo_b; - unsigned foo_c:1; - }; - -- For variable declaration outside a struct, either collect all the - declarations of the same type on a single line, or use one variable - per line if the variables purpose needs to be commented. Eg: - char *a, *b, c; - - or: - - char *a, *b; - char c; /* comments for c */ - -- Avoid magic numbers because no-one has a clue (including the author) of - what it means after a month. - -- Function definitions should start the name of the function in column - one. This is useful because it makes searching for function definitions - fairly trivial. Eg: -static char * -concat(char *s1, char *s2) -{ - body of the function -} - -- Function and variables local to a file should be static. -- Separate two successive functions with one blank line. -- Include parameter names with their datypes in function declaration. Eg: -void function(int param); - -- Functions should be short and sweet, and do just one thing. They should - fit on one or two screenfuls of text (80 x 24 screen size), 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. - 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. -- Use const for function parameters passed by reference, if the passed - pointer has no side effect. - -- C style comments only. Don't use // for single line comments. Instead - use /* ... */ style. -- For multi-line comments use the following style - /* - * This is the preferred style for multi-line - * comments in the Linux kernel source code. - * Please use it consistently. - * - * Description: A column of asterisks on the left side, - * with beginning and ending almost-blank lines. - */ - -- To comment out block of code spanning several lines use preprocessor - directive "#ifdef 0 ... #endif" - -- Please write a brief comment at the start of each source file, with the - file name and a line or two about the overall purpose of the file. - -- All major functions should have comments describing what they do at the - head of the function. Avoid putting comments in the function body unless - absolutely needed. If possible, add a comment on what sorts of arguments - the function gets, and what the possible values of arguments mean and - what they are used for and the significance of return value if there is - one. It is not necessary to duplicate in words the meaning of the C - argument declarations, if a C type is being used in its customary fashion. - If there is anything nonstandard about its use (such as an argument of - type char * which is really the address of the second character of a - string, not the first), or any possible values that would not work the - way one would expect (such as, that strings containing newlines are not - guaranteed to work), be sure to say so. Eg: - -/* - * Try to acquire a physical address lock while a pmap is locked. If we - * fail to trylock we unlock and lock the pmap directly and cache the - * locked pa in *locked. The caller should then restart their loop in case - * the virtual to physical mapping has changed. - * - * Returns 0 on success and -1 on failure. - */ -int -vm_page_pa_tryrelock(pmap_t pmap, vm_paddr_t pa, vm_paddr_t *locked) -{ - ... - -- The comment on a function is much clearer if you use the argument names - to speak about the argument values. The variable name itself should be - lower case, but write it in upper case when you are speaking about the - value rather than the variable itself. Thus, “the inode number NODE_NUM” - rather than “an inode”. - -- Every struct definition should have an accompanying comment that - describes what it is for and how it should be used. - -- Finally, while comments are absolutely important to keep the code readable, - remember that the best code is self-documenting. Giving sensible names to - types and variables is much better than using obscure names that you must - then explain through comments. - -- Recommend using UPPERCASE for macro names. However, sometimes using - lowercase for macro names makes sense when macros masquerade as well-known - function calls. Eg, it makes sense to write the wrapper for the - standard free() function in lowercase to keep the readability - consistent: - -#define my_free(_p) do { \ - free(_p); \ - (_p) = NULL; \ -} while (0) - -- Use enums when defining more than one related constants. All enumeration - values are in UPPERCASE. -- Avoid macros as much as possible and use inline functions, enums and const - variables wherever you can. -- For macros encapsulating compound statements, right justify the backslashes - and enclose it in do { ... } while (0) -- For parameterized macros, all the parameters used in the macro body must - be surrounded by parentheses. Eg: - #define ADD_1(_x) ((_x) + 1) - -- Use sizeof(varname) instead of sizeof(type) whenever possible. Eg: - char *p; - p = malloc(sizeof(*p)); /* good example */ - p = malloc(sizeof(char)); /* bad example */ - -- All variables should be declared at the beginning of a scope block {..}. - It is even preferred to declare all variables at the beginning of the - function so that all the local variable declarations is in one place and - we can see the comprehensive list in one glance. -- Global structs should be declared at the top of the file in which they - are used, or in separate header files if they are used in multiple - source files. -- Declarations of external functions and functions to appear later in the - source file should all go in one place near the beginning of the file, - somewhere before the first function definition in the file or else - should go in a header file. -- Use of extern should be considered as evil, if it is used in header files - to reference global variables. -- Don’t put extern declarations inside functions. - -- Usually every *.c file should have an associated *.h file. There are some - exceptions to this rule, such as unit tests and small *.c files containing - just the main() function. -- Every header file in the source code must have preprocessor conditional - to prevent the header file from being scanned multiple times and avoiding - mutual dependency cycles. Alternatively you can use #pragma once directive, - as it avoids name clashes and increases the compile speed. Eg, for a - header file named foo.h, the entire contents of the header file must be - between the guard macros as follows: - -#ifndef _FOO_H_ -#define _FOO_H_ -... -#endif /* _FOO_H_ */ - -Or, - -#pragma once -#ifndef _FOO_H_ -#define _FOO_H_ -... -#endif /* _FOO_H_ */ - -- Don't use #include when a forward declaration would suffice. -- Functions defined in header files should be static inline. - -- Don’t make the program ugly just to placate GCC when extra warnings options - such as ‘-Wconversion’ or ‘-Wundef’ are used. These options can help in - finding bugs, but they can also generate so many false alarms that that - it hurts readability to silence them with unnecessary casts, wrappers, and - other complications. - -- Conditional compilation: when supporting configuration options already - known when building your program we prefer using if (... ) over conditional - compilation, as in the former case the compiler is able to perform more - extensive checking of all possible code paths. Eg, use: - - if (HAS_FOO) - ... - else - ... - -instead of: - - #ifdef HAS_FOO - ... - #else - ... - #endif - - A modern compiler such as GCC will generate exactly the same code in both - cases and of course, the former method assumes that HAS_FOO is defined as - either 0 or 1. - -- Finally, rules are rules. Sometimes they are sensible and sometimes not - and regardless of your preference, we would like you to follow them. - A project is easier to follow if all project contributors follow the style - rules so that they can all read and understand everyone's code easily. But - remember, like all good rules, they are exceptions where it makes sense not - to be too rigid on the grounds of common sense and consistency! diff --git a/docs/coding_style.rst b/docs/coding_style.rst new file mode 100644 index 000000000..0a6a7bdfe --- /dev/null +++ b/docs/coding_style.rst @@ -0,0 +1,583 @@ +Introduction +============ + +The C Style Guide is a set of guidelines and conventions that encourage +good code. While some suggestions are more strict than others, you should +always practice good judgement. + +If following the guide causes unnecessary hoop-jumping or otherwise +less-readable code, *readability trumps the guide*. However, if the more +readable variant comes with perils or pitfalls, readability may be +sacrificed. + +Consistency is crucial. Without consistent application, there simply is no style +to speak of [#fn1]_. Stay in sync with the rest of the codebase; when you want +to change a rule or style, change it everywhere. + +Contents +-------- + +.. toctree:: + :maxdepth: 1 + + coding_style + + +C Standard +========== + +- Use ``-std=c11`` when compiling +- Avoid ``_Atomic``, ``_Generic`` and ``_Thread_local``, for now. We will + embrace ``C11`` fully when Twitter's official ``GCC`` is bumped to 4.9. + +Indentation +=========== + +- Do not use literal tabs. Expand tabs to **four** spaces instead. +- Use **four** spaces for every indentation level. +- Do not use more than **four** levels of indentation unless there's a good + reason. +- Make sure that your editor does not leave space at the end of each line. +- When a block of code resembles a table, such as in a macro-block or struct + definition, start each field on a ``4k+1`` column, so all fields are **four** + space aligned. + + .. code-block:: c + + /* name type description */ + #define FOO_METRIC(ACTION) \ + ACTION( foo_free, METRIC_GAUGE, "# free foo" )\ + ACTION( foo_borrow, METRIC_COUNTER, "# foos borrowed" )\ + ACTION( foo_return, METRIC_COUNTER, "# foos returned" )\ + /* name starts on column 13 + * type starts on column 29 + * description on column 45 + */ + + struct foo { + struct foo *next; + struct mumble amumble; + int bar; + }; + /* type starts on column 5, name on column 21 */ + + +Switch alignment +---------------- + +Align the ``switch`` keyword and the corresponding ``case`` and ``default`` +keywords to the same column. For example: + +.. code-block:: c + + switch (alphabet) { + case 'a': + case 'b': + printf("I am a or b\n"); + break; + default: + break; + } + + +Naming +====== + +- Use ``snake_case`` for the names of variables, functions, and files. +- Use your own judgement when you name variables and be as spartan as possible, + abbreviation is common in C. + For example, do not use a name like ``this_variable_is_a_temporary_counter``. + + +Types +===== + +- For variables of the following types: + + - ``int`` + - ``char`` + - ``short`` + - ``long`` + + Prefer the following types declared in the ```` header: + + - ``int8_t`` + - ``uint8_t`` + - ``int16_t`` + - ``uint16_t`` + - ``int32_t`` + - ``uint32_t`` + - ``int64_t`` + - ``uint64_t`` + + The latter types give us more predictable value range and memory layout on + different platforms. + +- Use the `bool` type for boolean data. You have to include the ```` + header. +- Always use the ``size_t`` type when you work with: + + - Sizes of objects + - Memory ranges + + +Line length +=========== + +- Limit each line to 80 columns or less. +- If you have to wrap a longer statement, put the operator at the end of the + line and use **eight** spaces to indent the next line. Indentation on the + next level is not affected. For example: + + .. code-block:: c + + while (cnt < 20 && this_variable_name_is_too_long && + ep != NULL) { + z = a + really + long + statement + that + needs + + two + lines + gets + indented + four + spaces + + on + the + second + and + subsequent + lines; + } + + and: + + .. code-block:: c + + int a = function(param_a, param_b, param_c, param_d, param_e, param_f, + param_g, param_h, param_i, param_j, param_k, param_l); + + +Braces +====== + +- Always use braces for all conditional blocks (``if``, ``switch``, ``for``, + ``while``, and ``do``), even for single statement conditional blocks (remember + the ``goto fail`` bug by Apple?). For example: + + .. code-block:: c + + if (cond) { + stmt; + } + +- For non-function statement blocks, put the opening brace at the end of the + first line and the closing brace in a new line. For example: + + .. code-block:: c + + if (x) { + foo(); + } + +- For functions, put the opening brace at the beginning of the second line + and the closing brace in a new line. For example: + + .. code-block:: c + + int + function(int x) + { + body of the function + } + +- Place the closing brace in its own line, except when it is part of the same + statement, such as a ``while`` in a ``do``-statement or an ``else`` in + an ``if``-statement. For example: + + .. code-block:: c + + do { + body of do-loop + } while (condition); + + and, + + if (x == y) { + .. + } else if (x > y) { + ... + } else { + .... + } + + +Infinite loops +============= + +Create infinite loops with ``for`` statements, not ``while`` statements. +For example: + +.. code-block:: c + + for (;;) { + stmt; + } + + +Spaces +====== + +- Do not use a space after a function name. +- Use space after keywords, except after the ``sizeof``, ``typeof``, ``alignof`` + and ``__attribute__`` keywords, since they are used like functions. +- Do not add spaces inside parenthesized expressions. For example: + + .. code-block:: c + + s = sizeof( sizeof(*p)) ); /* Bad example */ + s = sizeof(sizeof(*p)); /* Good example */ + +- When declaring pointers, place the asterisk ('*'') adjacent to the variable + name, not the type name. For example: + + .. code-block:: c + + int + function(int *p) + { + char *p; + body of the function + } + +- Use one space around most binary and ternary operators, such as any of these: + + ``=`` ``+`` ``-`` ``<`` ``>`` ``*`` ``/`` ``%`` ``|`` ``&`` ``^`` + ``<=`` ``>=`` ``==`` ``!=`` ``?`` ``:`` + + Do not add spaces after unary operators: + + ``&`` ``*`` ``+`` ``-`` ``~`` ``!`` ``sizeof`` ``typeof`` ``alignof`` + ``__attribute__`` ``defined`` + + Do not add spaces before the postfix increment and decrement unary operators: + + ``++`` ``--`` + + Do not add spaces around the ``.`` and ``->`` structure member operators. + +- Do not add spaces after casts. For example: + + .. code-block:: c + + int q = *(int *)&p + + +Type definitions +================ + +In general, do not use ``typedef`` for the purpose of hiding structures. +Typedefs used this way are problematic because they do not properly hide their +underlying type; for example, you need to know if the typedef is the structure +itself or a pointer to the structure. In addition, they must be declared exactly +once, whereas an incomplete structure type can be mentioned as many times as +necessary. Typedefs are difficult to use in stand-alone header files: the header +that defines the typedef must be included before the header that uses it, or by +the header that uses it (which causes namespace pollution), or there must be a +back-door mechanism for obtaining the typedef. + +That said, ``typedef`` can be helpful sometimes. For example, it is routinely +used to clarify the nature of an argument or return value, which can be of a +rather generic type such as ``void *``. It is also common to rename ``enum``. + +To make ``typedef`` names more informative and regular, we use the following +suffixes: + + - ``_e`` for ``enum`` + - ``_f`` for floating point numbers, regardless of size + - ``_i`` for signed integers, regardless of size + - ``_u`` for unsigned integers, regardless of size + - ``_fn`` for function pointers + - ``_p`` for other pointer type + - ``_st`` for ``struct`` + + +Forward Declaration +=================== + +Prefer using forward declaration over including another header for type- +declaration only. Forward declaration such as ``struct request;`` is feasible +if none of its members are directly accessed, such as when it's used in function +declaration. + + +Functions +========= + +- Declare functions that are local to a file as static. +- Place function types in their own line preceding the function. For example: + + .. code-block:: c + + static char * + function(int a1, int a2, float fl, int a4) + { + ... + +- Separate two successive functions with one blank line. +- Include parameter names with their dataypes in the function declaration. For + example: + + .. code-block:: c + + void function(int param); + +- When you use a wrapper function, name the wrapped function with the same name + as the wrapper function preceded by an underscore ('_'). Wrapped functions + are usually static. For example: + + .. code-block:: c + + static int + _fib(int n) + { + ... + } + + int + fib(int n) + { + ... + _fib(n); + ... + } + +- Create functions that are short and sweet. Functions should do just one + thing and fit on one or two screenfuls of text (80x24 screen size). + + 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 many + different cases, it is acceptable to have a longer function. + + Another measure of function complexity is the number of local variables. They + should not exceed 5-10. If your function has more than that, re-think the + function and split it into smaller pieces. A human brain can + generally easily keep track of about seven different things; anything more + and it gets confused. You may need to come back to your function and + understand what you did two weeks from now. + + +Goto statements +=============== + +- Use ``goto`` statements judiciously. Never use them to jump out of the + current function. Almost the only case where ``goto`` statements are helpful + is when a flow can exit from multiple locations within a function, and the + same clean-up logic applies to all of them. + + + .. code-block:: c + + int + fun(void) + { + int result = 0; + char *buffer; + buffer = malloc(1024); + if (buffer == NULL) { + return -1; + } + if (condition1) { + while (loop1) { + ... + } + result = 1; + goto out; + } + ... + out: + free(buffer); + return result; + } + + + +Comments +======== + +- Do not use ``//`` for single line comments. Instead, use the ``/* ... */`` + style. + +- For multi-line comments, use the following style: + + .. code-block:: c + + /* + * This is the preferred style for multi-line + * comments in the Linux kernel source code. + * Please use it consistently. + * + * Description: A column of asterisks on the left side, + * with beginning and ending almost-blank lines. + */ + +- To comment out blocks of code spanning several lines, use + ``#ifdef 0 ... #endif``. + +- Add comments before all major functions to describe what they do. Do not put + comments in the function body unless absolutely needed. For example: + + .. code-block:: c + + /* + * Try to acquire a physical address lock while a pmap is locked. If we + * fail to trylock we unlock and lock the pmap directly and cache the + * locked pa in *locked. The caller should then restart their loop in + * case the virtual to physical mapping has changed. + */ + int + vm_page_pa_tryrelock(pmap_t pmap, vm_paddr_t pa, vm_paddr_t *locked) + { + ... + + + +Other naming conventions +======================== + +- Use UPPERCASE for macro names. + +- Use ``enum`` to define several related constants. Use UPPERCASE for all + enumeration values. + +- Avoid macros as much as possible and use inline functions wherever you can. + +- For macros encapsulating compound statements, right-justify the backslashes + and enclose the statements in a ``do { ... } while (0)`` block. + +- For parameterized macros, add parentheses to all the parameters. For example: + + .. code-block:: c + + #define ADD_1(x) ((x) + 1) + + + +Inclusion +========= + +- Rule of thumb- local to global: first include header of the same name as + source, followed by headers in the same project, and external/system headers + last. +- Organize header inclusion in blocks, separated by blank line(s). For example, + headers that are shipped with the project and system headers should be in + separate clusters. +- Sort inclusions within the same block in alphabetic order. + + .. code-block:: c + + /* File: foo.c */ + #include "foo.h" /* first block: own header */ + + #include "bar.h" /* second block: headers from current project */ + #include "util/baz.h" + + #include /* third block: system/library headers */ + #include + #include + + +Structures +========== + +- To determine the size of a data structure, use some data of that type instead + of the type itself. For example: + + .. code-block:: c + + char *p; + p = malloc(sizeof(*p)); /* Good example */ + p = malloc(sizeof(char)); /* Bad example */ + +- Declare each variable in a structure in a separate line. Try to make the + structure readable by aligning the member names and comments using spaces. + Use a modest number of spaces if they suffice to align most of the member + names. Separate names that follow extremely long types with a single space. + + .. code-block:: c + + struct foo { + struct foo *next; /* List of active foo. */ + struct mumble amumble; /* Comment for mumble. */ + int bar; /* Try to align the comments. */ + struct verylongtypename *baz; /* Won't fit in 2 tabs. */ + }; + struct foo *foohead; /* Head of global foo list. */ + +- Declare major structures at the top of the file in which they are used, or + in separate header files if they are used in multiple source files. + Use of the structures should be by separate declarations and should be + ``extern`` if they are declared in a header file. + + +Pointers +======== + +- Use ``NULL`` as the null pointer constant (instead of ``0``). + +- Compare pointers to ``NULL``. For example: + + .. code-block:: c + + (p = f()) == NULL + + Do not compare to zero the integer. For example: + + .. code-block:: c + + !(p = f()) + +- Do not use ``!`` for comparisons (unless the variable is of boolean type). For + example: + + .. code-block:: c + + if (*p == '\0') + + The following snippet is a bad example: + + .. code-block:: c + + if (!*p) /* assume p is of type char * */ + +- Use ``const`` for function parameters if the pointer has no side effect. + +- Functions in charge of freeing an object should take a pointer to the intended + pointer to be freed, and set the pointer to the object to ``NULL`` before + returning. This prevents dangling pointers that are often discovered long + after ``free`` is called. + + .. code-block:: c + + void + destroy_buffer(struct buffer **pb) + { + free(*pb); + *pb = NULL; + } + +- Dynamically allocated structures should always initialize their members of + pointer type as soon as possible, to avoid the dangling pointer problem. + + +Macros +====== + +- Prefer ``static inline`` functions over macros. Macros often have unintended + side effects, for example: + + .. code-block:: c + + #define MAX(a,b) ((a) > (b) ? (a) : (b)) + + When used as in ``MAX(x++, y++)``, will increment either ``x`` or ``y`` twice, + which is probably not intended by the caller. + + +.. rubric:: Footnotes + +.. [#fn1] Frederick Brooks gave a definition of "style" in his book, The Design + of Design, which begins with "Style is a set of different repeated + microdecisions...". The book talked about the importance of Consistency in + the pages leading to this definition, starting from page 142, where the + author claimed that "consistency underlies all principles of quality".