Coding Style

To maintain consistency within the CAM software source code a series of rules and guidelines have been created; these form the project’s coding style.

Source Code

Unicode

The source code must use the UTF-8 encoding. Comments, documentation and strings may use non-ASCII characters when required (e.g. Greek letters used for units).

License Headers

All files must begin with a license header of the following form:

Critical Application Monitoring (CAM)

SPDX-FileCopyrightText: <text>Copyright <years> Arm Limited
and/or its affiliates <[email protected]></text>
SPDX-License-Identifier: BSD-3-Clause

Where ‘<years>’ is a list of years the file received updates. Contiguous years may be written in the form of a hyphened range, example: ‘2019, 2021-2023’.

C Code Style

Clang Format

To aid in establishing a uniform style across the code-base, this project uses Clang Format. When contributing patches, care should be taken to ensure that code has been formatted according to the rules laid down in the .clang-format file, and that deviations occur only where the tool is unable to format code reasonably.

Braces

Conditional statements and iteration statements with a single line or multiple lines of code must be surrounded by braces:

if (condition) {
  function_call(
      long_variable_name_x,
      long_variable_name_y,
      long_variable_name_z);
}

This rule applies also to an if-else chain:

if (condition) {
    function_call(
        long_variable_name_x,
        long_variable_name_y,
        long_variable_name_z);
} else {
    function_call_b();
}

Empty loop statements must use continue:

while (condition) {
  continue;
}

Operators

When using operators like sizeof and alignof, where possible use the value-based version over the type-based version:

int counter;

sizeof(counter); /* Preferred over sizeof(int) */

Operator Precedence

Do not rely on the implicit precedence and associativity of operators. Use parentheses to make precedence and associativity explicit:

if ((a == 'a') || (x == 'x')) {
    do_something();
}

Parentheses around a unary operator and its operand may be omitted:

if (!a && *b) {
    do_something();
}

Header Guards

All headers must be wrapped with include guards to prevent accidental multiple definitions of header contents. The definition name should be the upper-case file name followed by _H. An example for a file named cam_mm.h follows:

#ifndef CAM_MM_H
#define CAM_MM_H

(...)

#endif /* CAM_MM_H */

Inclusion Policy

The closing endif statement should be followed directly by a single-line comment which replicates the full guard name. In long files this helps to clarify what is being closed.

Macros and Constants

All macro and constant names must be written in upper-case to differentiate them from functions and non-constants.

Logical groupings of constants should be defined as enumerations with a common prefix, so that they can be used as parameter types and in constant expressions. Enumerations that contain a “number of elements” value must use the _COUNT suffix, and the final enumeration value should include a comma.

enum cam_msg_a2s_id {
    CAM_MSG_A2S_ID_INIT = 1,
    CAM_MSG_A2S_ID_START,
    CAM_MSG_A2S_ID_STOP,
    CAM_MSG_A2S_ID_EVENT,
    CAM_MSG_A2S_ID_COUNT,
};

void cam_process_msg_id(enum cam_msg_a2s_id id)
{
    (...)
}

Symbol Naming

Function, variable, file name and type names must:

  • Be written in lower-case

  • Have compound words separated by underline characters (_)

Avoid using:

  • Camel case syntax (e.g. criticalAppMonitor)

  • Hungarian notation, encoding types within names (e.g. int iSize)

Loop Indices

It is acceptable to use the following common placeholder names for loop indices:

  • i

  • j

  • k

Types

Avoid defining custom types with the typedef keyword except for opaque types. Names defined with typedef must use the _t suffix.

Comments

To ensure a consistent look, the preferred style for single-line comments is to use the C89 style of paired forward-slashes and asterisks, ending with no punctuation:

/* A short, single-line comment */

Multi-line comments should follow a similar style, and always end with punctuation:

/*
 * This is a very, very, very, very long multi-line comment where each line
 * starts with an asterisk and paragraphs ends with punctation.
 */

Doxygen comments follow only the second style, for consistency in the generated documentation:

/*!
 * \brief Hello, World.
 */

Preprocessor if 0 is preferred for commenting out blocks of code where it is necessary to do so, as these can be nested (unlike multi-line comment blocks).

void function_a(int x, int y)
{
    (...)
}

#if 0
void function_b(int x, int y)
{
    (...)
}
#endif

Prefer functions to function-like macros where possible. Avoid using the inline keyword, as inlining sites are better-determined by the compiler.

Initialization

When literals require explicit literal initialization, avoid implicit casts by using the proper integer literal suffix or initializer:

void *p = NULL;
unsigned int u = 0u;
float f = 0.0f;
double d = 0.0;
char c = '\0';

Array and structure initialization should use designated initializers. These allow elements to be initialized using array indices or structure field names without a fixed ordering:

uint32_t value_array[3] = {
    [2] = 800,
    [0] = 675,
};

struct cam_struct x = {
    .name = "example",
    .value = 100,
};

Doxygen Comments

libcam APIs are documented using Doxygen comments.

At a minimum:

  • All functions and structures must have at least a brief tag

  • All functions must document their parameters (if any) with the param tag

    • Input parameters must use param[in]

    • Output parameters must use param[out]

    • Input/output parameters must use param[in, out]

  • All functions returning a value should use the return and, optionally, the retval tag to document their return value * return should document what the type of the return value represents * retval should document what individual return values represent

Alignment and indentation:

  • Documentation must also obey the 80 column limit

  • Multiple lines of documentation on an entry (e.g. details) must be indented using the equivalent of two 4-space based tabs from the first column (see example below)

Function documentation example:

/*!
 * \brief Retrieve the library version.
 *
 * \details This function retrieve the current of the library.
 *
 * \param[out] major Pointer to the major version number.
 *
 * \param[out] minor Pointer to the minor version number.
 *
 * \retval 0 The version is retrieved with success.
 * \retval -1 Failed to retrieve the library version. The returned major and
 *    minor are invalid.
 */
int cam_version(unsigned int *major, unsigned int *minor);

Structure documentation example:

/*!
 * \brief A structure example.
 *
 * \details This is an example of a structure for the code style documentation.
 */
struct cam_structure {
    /*!
     * \brief Example field.
     */
    unsigned int example;
};

Python

Python based tools must follow the PEP8 specification. This is enforced with the pycodestyle tool.

Python code must be linted with pylint.

Sphinx-based Documents

Sphinx-based documents must use the following style.

Headings

The following headings style should be used:

########################
Heading 1 using overline
########################

************************
Heading 2 using overline
************************

Heading 3
=========

Heading 4
---------

Heading 5
^^^^^^^^^

Heading 6
"""""""""

Code blocks

Use the code-block directive and specify the programming language. As an example:

.. code-block:: python

  import this

Alignment and Indentation

Documentation source must obey the 80 column limit.

The indentention must be 2-spaces.