wiki:Developer/Coding/Conventions

Coding Conventions

The style of RTEMS is generally consistent in the core areas. This page attempts to capture generally accepted practices. When in doubt, consult the code around you or look in cpukit/rtems. See the sister page Doxygen Recommendations for examples that illustrate style rules and Doxygen usage.

Source Documentation

  • Use Doxygen according to our Doxygen Recommendations.
  • Start each file with a brief description followed by a license. See Boilerplate File Header.
  • Use /* */ comments.
  • Use comments wisely within function bodies, to explain or draw attention without being verbose.
  • Use English prose and strive for good grammar, spelling, and punctuation.
  • Use TODO: with a comment to indicate code that needs improvement. Make it clear what there is to do.
  • Use XXX or FIXME to indicate an error/bug/broken code.

Licenses

  • The RTEMS License is the typical and preferred license.
    • 2- and 3-clause BSD, MIT, and other OSI-approved non-copyleft licenses that permit statically linking with code of different licenses are acceptable.
    • GPL licensed code is NOT acceptable, neither is LGPL. See this blog post explanation for more information.
    • Advertising obligations are NOT acceptable, but restrictions are permissible.

Language and Compiler

  • Use C99.
  • Treat warnings as errors: eliminate them.
  • Favor C, but when assembly language is required use inline assembly if possible.
  • Do not use compiler extensions.
  • Use the RTEMS_ macros defined in score/basedefs.h for abstracting compiler-specific features.
  • Use NULL for the null pointer, and prefer to use explicit checks against NULL, e.g. 'if ( ptr != NULL )' instead of 'if ( !ptr )'.
  • Use '(void) unused;' to mark unused parameters and set-but-unused variables immediately after being set.
  • Do not put function prototypes in C source files, any global functions should have a prototype in a header file and any private function should be declared static.
  • Declare global variables in exactly one header file. Define global variables in at most one source file. Include the header file declaring the global variable as the first include file if possible to make sure that the compiler checks the declaration and definition and that the header file is self-contained.

Formatting

  • Use spaces instead of tabs.
  • Use two spaces for indentation, four spaces for hanging indentation.
  • Adhere to a limit of 80 characters per line.
  • Put function return types and names on one line if they fit.
  • Put function calls on one line if they fit.
  • No space between a function name or function-like macro and the opening parens.
  • Put braces on the same line as and one space after the conditional expression ends.
  • Put the opening brace of a function definition one line after the closing parenthesis of its prototype.
  • Put a single space inside and outside of each parenthesis of a conditional expression.
    • Exception: never put a space before a closing semi-colon.
  • Put a single space before and after ternary operators.
  • Put a single space before and after binary operators.
  • Put no space between unary operators (e.g. *, &, !, ~, ++, --) and their operands.
  • No spaces around dereferencing operators (-> and .).
  • Do not use more than one blank line in a row.
  • Do not use trailing whitespace at the end of a line.

Readability

  • Understand and follow the naming rules.
  • Use typedef to remove 'struct', but do not use typedef to hide pointers or arrays.
    • Exception: typedef can be used to simplify function pointer types.
  • Do not mix variable declarations and code.
  • Declare variables at the start of a block.
  • Only use primitive initialization of variables at their declarations. Avoid complex initializations or function calls in variable declarations.
  • Do not put unrelated functions or data in a single file.
  • Do not declare functions inside functions.
  • Avoid deep nesting by using early exits e.g. return, break, continue.
    • Parameter checking should be done first with early error returns.
    • Avoid allocation and critical sections until error checking is done.
    • For error checks that require locking, do the checks early after acquiring locks.
    • Use of 'goto' requires good reason and justification.
  • Test and action should stay close together.
  • Avoid complex logic in conditional and loop statements.
  • Put conditional and loop statements on the line after the expression.
  • Favor inline functions to hide compile-time feature-conditioned compilation.
  • Define non-inline functions in a .c source file.
  • Declare all global (non-static) functions in a .h header file.
  • Declare and define inline functions in one place. Usually this is a *impl.h header file.
  • Declare and define static functions in one place. Usually this is toward the start of a .c file. Minimize forward declarations of static functions.
  • Function declarations should include variable names.
  • Avoid excess parentheses. Learn the operator precedence rules.
  • Always use parentheses with sizeof. This is an exception to the rule about excess parentheses.

Robustness

  • Check all return statuses.
  • Use debug assertions (assert).
  • Use const when appropriate for read-only function parameters and compile-time constant values.
  • Do not hard code limits such as maximum instances into your code.
  • Prefer to use sizeof(variable) instead of sizeof(type).
  • Favor C automatic variables over global or static variables.
  • Use global variables only when necessary and ensure atomicity of operations.
  • Do not shadow variables.
  • Avoid declaring large buffers or structures on the stack.
  • Favor mutual exclusion primitives over disabling preemption.
  • Avoid unnecessary dependencies, such as by not calling printf() on error paths.
  • Avoid inline functions and macros with complicated logic and decision points.
  • Prefer inline functions, enum, and const variables instead of CPP macros.
  • CPP macros should use a leading underscore for parameter names and avoid macro pitfalls.

Portability

  • Think portable! RTEMS supports a lot of target hardware.
  • For integer primitives, prefer to use precise-width integer types from C99 stdint.h.
  • Write code that is 16-bit, 32-bit, and 64-bit friendly.

Maintainability

  • Minimize modifications to third party code.
  • Keep it simple! Simple code is easier to debug and easier to read than clever code.
  • Share code with other architectures, CPUs, and BSPs where possible.
  • Do not duplicate standard OS or C Library routines.

Performance

  • Prefer algorithms with the lowest order of time and space for fast, deterministic execution times with small memory footprints.
  • Understand the contraints of real-time programming. Limit execution times in interrupt contexts and critical sections, such as Interrupt and Timer Service Routines (TSRs).
  • Functions used only through function pointers should be declared 'static inline' (RTEMS_INLINE_ROUTINE)
  • Prefer to ++preincrement instead of postincrement++.
  • Avoid using floating point except where absolutely necessary.

Miscellaneous

  • If you need to temporarily change the execution mode of a task/thread, restore it.
  • If adding code to cpukit be sure the filename is unique since all files under that directory get merged into a single library.

Layering

Exceptions to the Rules

  • Minimize reformatting existing code in RTEMS unless the file undergoes substantial non-style changes.
  • Third-party code should not be reformatted to fit RTEMS style. Exception: unmaintained third-party code adopted and maintained by RTEMS may be reformatted, subject to the above rules.

Tools

Some of the above can be assisted by tool support. Feel free to add more tools, configurations, etc here.

Last modified 12 months ago Last modified on Apr 9, 2016, 9:02:26 PM

Attachments (1)

Download all attachments as: .zip