-
Notifications
You must be signed in to change notification settings - Fork 3
CodingStyle
Here is a brief description of the preferred coding style for OpenISR, which is based on the Linux kernel coding style. This is intended mostly for C code; parts (especially indentation) apply to code in any language.
Indentation. One tab character per level. (Tab stops are set every 8 columns.) No line should pass column 80. Continuation lines should be indented three tabs beyond the line they are continuing. Do not leave whitespace at the end of lines. Don't try to align variable declarations. (Some older Perl code uses 4 spaces per level; in these files, continue to use that style. Older code rampantly places whitespace at the end of blank lines; avoid introducing additional end-of-line whitespace into such files.)
Code structure. K&R brace placement. No more than one statement or variable declaration per line. (In other words, no int a, b;.) Local variable declarations should go at the top of the function, followed by a blank line. The body of an if, for, or while statement should go on its own line, and should not be braced if there's only one line of body, except that if any branch of an if ... else if ... else block requires braces, all branches should have them. case statements in a switch should be aligned with the switch statement. goto labels should be on a line by themselves and should start in the first column. Do not parenthesize the return value in return statements.
File structure. C files should contain includes, then structure definitions if any, then static and global variable declarations, then code. Operations structures (those containing a list of function pointers) should be defined after the functions they point to.
Structure initialization. Use tagged initialization format (.foo = bar). This is optional when initializing a const array of structs (e.g. command-line parser configuration).
Spacing. Place spaces before and after assignment, comparison, mathematical, and ?: operators; after casts; after keywords like if and while; and after semicolons in for tests. Do not place a space after the function name in a function call, between parens and the things they enclose, or between a unary operator and its argument. sizeof and typeof should be treated as functions. The asterisk in a pointer should run up against the variable name. (Some older C code does not place spaces around assignment operators.)
typedefs. Should generally not be used, since they obscure the underlying type. typedefs may be used for basic types used widely in a way that has special semantics (e.g. mrpc_status_t). typedefs may also be used for function signatures, in cases where pointers to functions with that signature are declared in more than one place. Note that the typedef should be for the function, not a pointer to it, e.g. void (foo)(int) rather than void (*foo)(int).
Comments. Use C89 /* */, not C99 //. Comments should add clarity, not noise. Focus on writing clear code, and comment only particularly obscure or tricky parts.
Function signatures. In C, a function that takes no arguments must specify "void", e.g. int foo(void). Where practical, use "const" for pointer parameters to data which is not modified.
Macros. Never use them when a function can be used. static inline functions should be used in header files instead of function-style macros. If unavoidable, enclose in parentheses (for expressions), or do {...} while 0 for multi-statement macros.
Constants. It is generally preferable to use enums rather than a series of #defines.
Conditional compilation. Do not clutter the code with #ifdefs. If necessary for portability, place the conditional part in a header (e.g., alternate definitions of a static inline function) and use it unconditionally from the .c file.
Headers. There is generally one internal header file per program, giving global structure definitions, then prototypes of non-static functions grouped by the source file in which they are defined.
Declarations. All non-static functions should have a prototype (in the internal header file). When possible, static functions should not; place them before the functions that call them.
Functions. Functions should do one thing. If there's a corner case which requires a lot of code to handle, put that code in a helper function rather than inline.
Encapsulation. Where possible, encapsulate a particular type of knowledge in a subsystem implemented in a single source file. The subsystem will have handle allocation and free functions and functions operating on that handle. (And possibly global initialization and shutdown functions.) The handle should be a struct foo *, where the internal header file contains a struct foo; declaration and the C file contains struct foo {...};. Use static functions whenever possible.
Allocation and freeing. Allocation/freeing of a structure type should usually be done in helper functions. Use the glib slice allocator when possible, g_malloc() otherwise. Exception: XDR structs must always use malloc()/free(), and do not need an allocation helper. The XDR free helper is automatically generated by miniRPC. (See the generated *_minirpc.h file.)
Error backout. In functions with complicated error backout, it's better to have the backout code at the bottom of the function, after the normal return path, and goto the right place in it, rather than repeating backout code in every error test.
Libraries. Libraries (miniRPC, libisrcrypto, etc.) should be careful to only export those symbols which are part of its public API. In other words, there will be three levels of visibility: static (only this source file), undeclared (only within library code), and exported (visible outside the library). "exported" is #defined to whatever compiler magic is needed to implement this. Note that some compilers do not support hiding non-static symbols, so all non-static, non-exported symbols must be named according to the same convention as exported library functions to avoid namespace pollution. The library's internal header should require some private macro to be defined before it is included, and #error otherwise, to prevent the header from being included accidentally by programs merely wishing to use the library.