{"id":20434999,"url":"https://github.com/majerle/c-code-style","last_synced_at":"2025-05-14T18:04:23.424Z","repository":{"id":37580365,"uuid":"144600839","full_name":"MaJerle/c-code-style","owner":"MaJerle","description":"Recommended C code style and coding rules for standard C99 or later","archived":false,"fork":false,"pushed_at":"2025-05-02T10:19:45.000Z","size":176,"stargazers_count":1156,"open_issues_count":0,"forks_count":239,"subscribers_count":51,"default_branch":"main","last_synced_at":"2025-05-02T11:32:47.923Z","etag":null,"topics":["c","c-code-style","c-rules","coding","rules","style"],"latest_commit_sha":null,"homepage":"http://majerle.eu","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MaJerle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":["paypal.me/tilz0R"]}},"created_at":"2018-08-13T15:46:02.000Z","updated_at":"2025-05-02T10:19:50.000Z","dependencies_parsed_at":"2025-04-06T08:11:10.659Z","dependency_job_id":"4b8e355e-07bb-405c-af44-135b0ba644eb","html_url":"https://github.com/MaJerle/c-code-style","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaJerle%2Fc-code-style","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaJerle%2Fc-code-style/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaJerle%2Fc-code-style/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MaJerle%2Fc-code-style/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MaJerle","download_url":"https://codeload.github.com/MaJerle/c-code-style/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254198452,"owners_count":22030964,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","c-code-style","c-rules","coding","rules","style"],"created_at":"2024-11-15T08:29:59.275Z","updated_at":"2025-05-14T18:04:18.414Z","avatar_url":"https://github.com/MaJerle.png","language":"C","readme":"# Recommended C style and coding rules\n\nThis document describes C code style used by Tilen MAJERLE in his projects and libraries.\n\n## Table of Contents\n\n- [Recommended C style and coding rules](#recommended-c-style-and-coding-rules)\n  - [Table of Contents](#table-of-contents)\n  - [The single most important rule](#the-single-most-important-rule)\n  - [Integration with VSCode](#integration-with-vscode)\n  - [Conventions used](#conventions-used)\n  - [General rules](#general-rules)\n  - [Comments](#comments)\n  - [Functions](#functions)\n  - [Variables](#variables)\n  - [Structures, enumerations, typedefs](#structures-enumerations-typedefs)\n  - [Compound statements](#compound-statements)\n    - [Switch statement](#switch-statement)\n  - [Macros and preprocessor directives](#macros-and-preprocessor-directives)\n  - [Documentation](#documentation)\n  - [Header/source files](#headersource-files)\n  - [Clang format integration](#clang-format-integration)\n  - [Artistic style configuration](#artistic-style-configuration)\n  - [Eclipse formatter](#eclipse-formatter)\n\n## The single most important rule\n\nLet's start with the quote from [GNOME developer](https://developer.gnome.org/documentation/guidelines/programming/coding-style.html) site.\n\n\u003e The single most important rule when writing code is this: *check the surrounding code and try to imitate it*.\n\u003e\n\u003e As a maintainer it is dismaying to receive a patch that is obviously in a different coding style to the surrounding code. This is disrespectful, like someone tromping into a spotlessly-clean house with muddy shoes.\n\u003e\n\u003e So, whatever this document recommends, if there is already written code and you are patching it, keep its current style consistent even if it is not your favorite style.\n\n## Integration with VSCode\n\nVScode comes with pre-installed `clang-format` tool (part of LLVM package) that has been design to help developers with auto-format tool during code development.\n\nAs such, it allows users to format code on file change (and save).\nWhen file is saved, vscode will try to invoke the clang-format and format the code. Rules to use are in `.clang-format` file. If clang-format cannot find the rules in the path of current file, it will go all the way up to the root, until one is found. If still none is available, default rules are then being used.\n\nThis repository contains always up-to-date `.clang-format` file with rules matching explained ones.\nYou can place the folder in the root or your project or even in the root of your software development projects -\u003e use one file for all!\n\nSome configurations shall be enabled:\n![VSCode configuration](images/vscode-settings.png) \n\n## Conventions used\n\nThe keywords *MUST*, *MUST NOT*, *REQUIRED*, *SHALL*, *SHALL NOT*, *SHOULD*, *SHOULD NOT*, *RECOMMENDED*, *NOT RECOMMENDED*, *MAY*, and\n   *OPTIONAL* in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174]\n\n## General rules\n\nHere are listed most obvious and important general rules. Please check them carefully before you continue with other chapters.\n\n- `clang-format` SHOULD be used with formatting file attached to this repository (version `15.x` is a minimum)\n- Use `C11` standard\n- Do not use tabs, use spaces instead\n- Use `4` spaces per indent level\n- Use `1` space between keyword and opening bracket\n```c\n/* OK */\nif (condition)\nwhile (condition)\nfor (init; condition; step)\ndo {} while (condition)\n\n/* Wrong */\nif(condition)\nwhile(condition)\nfor(init;condition;step)\ndo {} while(condition)\n```\n\n- Do not use space between function name and opening bracket\n```c\nint32_t a = sum(4, 3);              /* OK */\nint32_t a = sum (4, 3);             /* Wrong */\n```\n\n- Never use `__` or `_` prefix for variables/functions/macros/types. This is reserved for C language itself\n    - Prefer `prv_` name prefix for strictly module-private (static) functions\n    - Prefer `libname_int_` or `libnamei_` prefix for library internal functions, that should not be used by the user application while they MUST be used across different library internal modules\n- Use only lowercase characters for variables/functions/types with optional underscore `_` char\n- Opening curly bracket is always at the same line as keyword (`for`, `while`, `do`, `switch`, `if`, ...)\n```c\nsize_t i;\nfor (i = 0; i \u003c 5; ++i) {           /* OK */\n}\nfor (i = 0; i \u003c 5; ++i){            /* Wrong */\n}\nfor (i = 0; i \u003c 5; ++i)             /* Wrong */\n{\n}\n```\n\n- Use single space before and after comparison and assignment operators\n```c\nint32_t a;\na = 3 + 4;              /* OK */\nfor (a = 0; a \u003c 5; ++a) /* OK */\na=3+4;                  /* Wrong */\na = 3+4;                /* Wrong */\nfor (a=0;a\u003c5;++a)       /* Wrong */\n```\n\n- Use single space after every comma\n```c\nfunc_name(5, 4);        /* OK */\nfunc_name(4,3);         /* Wrong */\n```\n\n- Do not initialize `global` variables to any default value (or `NULL`), implement it in the dedicated `init` function (if REQUIRED).\n```c\nstatic int32_t a;       /* Wrong */\nstatic int32_t b = 4;   /* Wrong */\nstatic int32_t a = 0;   /* Wrong */\n```\n\u003e In embedded systems, it is very common that RAM memories are scattered across different memory locations in the system.\n\u003e It quickly becomes tricky to handle all the cases, especially when user declares custom RAM sections.\n\u003e Startup script is in-charge to set default values (.data and .bss) while other custom sections may not be filled with default values, which leads to variables with init value won't have any effect.\n\u003e\n\u003e To be independent of such problem, create init function for each module and use it to set\n\u003e default values for all of your variables, like so:\n\n```c\nstatic int32_t a;       /* OK */\nstatic int32_t b = 4;   /* Wrong - this value may not be set at zero \n                            if linker script\u0026startup files are not properly handled */\n\nvoid\nmy_module_init(void) {\n    a = 0;\n    b = 4;\n}\n```\n\n- Declare all local variables of the same type in the same line\n```c\nvoid\nmy_func(void) {\n    /* 1 */\n    char a;             /* OK */\n    \n    /* 2 */\n    char a, b;          /* OK */\n    \n    /* 3 */\n    char a;\n    char b;             /* Wrong, variable with char type already exists */\n}\n```\n\n- Declare local variables in order\n    1. Custom structures and enumerations\n    2. Integer types, wider unsigned type first\n    3. Single/Double floating point\n```c\nint\nmy_func(void) {\n    /* 1 */\n    my_struct_t my;     /* First custom structures */\n    my_struct_ptr_t* p; /* Pointers too */\n\n    /* 2 */\n    uint32_t a;\n    int32_t b;\n    uint16_t c;\n    int16_t g;\n    char h;\n    /* ... */\n\n    /* 3 */\n    double d;\n    float f;\n}\n```\n\n- Always declare local variables at the beginning of the block, before first executable statement\n- Always add trailing comma in the last element of structure (or its children) initialization (this helps clang-format to properly format structures). Unless structure is very simple and short\n```c\ntypedef struct {\n    int a, b;\n} str_t;\n\nstr_t s = {\n    .a = 1,\n    .b = 2,   /* Comma here */\n}\n\n/* Examples of \"complex\" structure, with or with missing several trailing commas, after clang-format runs the formatting */\nstatic const my_struct_t my_var_1 = {\n    .type = TYPE1,\n    .type_data =\n        {\n            .type1 =\n                {\n                    .par1 = 0,\n                    .par2 = 1, /* Trailing comma here */\n                }, /* Trailing comma here */\n        },  /* Trailing comma here */\n};\n\nstatic const my_struct_t my_var_2 = {.type = TYPE2,\n                                     .type_data = {\n                                         .type2 =\n                                             {\n                                                 .par1 = 0,\n                                                 .par2 = 1,\n                                             },\n                                     }};    /* Missing comma here */\nstatic const my_struct_t my_var_3 = {.type = TYPE3,\n                                     .type_data = {.type3 = {\n                                                       .par1 = 0,\n                                                       .par2 = 1,\n                                                   }}}; /* Missing 2 commas here */\n\n/* No trailing commas - good only for small and simple structures */\nstatic const my_struct_t my_var_4 = {.type = TYPE4, .type_data = {.type4 = {.par1 = 0, .par2 = 1}}};\n```\n\n- Declare counter variables in `for` loop\n```c\n/* OK */\nfor (size_t i = 0; i \u003c 10; ++i)\n\n/* OK, if you need counter variable later */\nsize_t i;\nfor (i = 0; i \u003c 10; ++i) {\n    if (...) {\n        break;\n    }\n}\nif (i == 10) {\n\n}\n\n/* Wrong */\nsize_t i;\nfor (i = 0; i \u003c 10; ++i) ...\n```\n\n- Avoid variable assignment with function call in declaration, except for single variables\n```c\nvoid\na(void) {\n    /* Avoid function calls when declaring variable */\n    int32_t a, b = sum(1, 2);\n\n    /* Use this */\n    int32_t a, b;\n    b = sum(1, 2);\n\n    /* This is ok */\n    uint8_t a = 3, b = 4;\n}\n```\n\n- Except `char`, `float` or `double`, always use types declared in `stdint.h` library, eg. `uint8_t` for `unsigned 8-bit`, etc.\n- Do not use `stdbool.h` library. Use `1` or `0` for `true` or `false` respectively\n```c\n/* OK */\nuint8_t status;\nstatus = 0;\n\n/* Wrong */\n#include \u003cstdbool.h\u003e\nbool status = true;\n```\n\n- Never compare against `true`, eg. `if (check_func() == 1)`, use `if (check_func()) { ... }`\n- Always compare pointers against `NULL` value\n```c\nvoid* ptr;\n\n/* ... */\n\n/* OK, compare against NULL */\nif (ptr == NULL || ptr != NULL) {\n\n}\n\n/* Wrong */\nif (ptr || !ptr) {\n\n}\n```\n\n- Always use *pre-increment (and decrement respectively)* instead of *post-increment (and decrement respectively)*\n```c\nint32_t a = 0;\n...\n\na++;            /* Wrong */\n++a;            /* OK */\n\nfor (size_t j = 0; j \u003c 10; ++j) {}  /* OK */\n```\n\n- Always use `size_t` for length or size variables\n- Always use `const` for pointer if function should not modify memory pointed to by `pointer`\n- Always use `const` for function parameter or variable, if it should not be modified\n```c\n\n/* When d could be modified, data pointed to by d could not be modified */\nvoid\nmy_func(const void* d) {\n\n}\n\n/* When d and data pointed to by d both could not be modified */\nvoid\nmy_func(const void* const d) {\n\n}\n\n/* Not REQUIRED, it is advised */\nvoid\nmy_func(const size_t len) {\n\n}\n\n/* When d should not be modified inside function, only data pointed to by d could be modified */\nvoid\nmy_func(void* const d) {\n\n}\n```\n\n- When function may accept pointer of any type, always use `void *`, do not use `uint8_t *`\n    - Function MUST take care of proper casting in implementation\n```c\n/*\n * To send data, function should not modify memory pointed to by `data` variable\n * thus `const` keyword is important\n *\n * To send generic data (or to write them to file)\n * any type may be passed for data,\n * thus use `void *`\n */\n/* OK example */\nvoid\nsend_data(const void* data, size_t len) { /* OK */\n    /* Do not cast `void *` or `const void *` */\n    const uint8_t* d = data;/* Function handles proper type for internal usage */\n}\n\nvoid\nsend_data(const void* data, int len) {    /* Wrong, not not use int */\n}\n```\n\n- Always use brackets with `sizeof` operator\n- Never use *Variable Length Array* (VLA). Use dynamic memory allocation instead with standard C `malloc` and `free` functions or if library/project provides custom memory allocation, use its implementation\n    - Take a look at [LwMEM](https://github.com/MaJerle/lwmem), custom memory management library\n```c\n/* OK */\n#include \u003cstdlib.h\u003e\nvoid\nmy_func(size_t size) {\n    int32_t* arr;\n    arr = malloc(sizeof(*arr) * n); /* OK, Allocate memory */\n    arr = malloc(sizeof *arr * n);  /* Wrong, brackets for sizeof operator are missing */\n    if (arr == NULL) {\n        /* FAIL, no memory */\n    }\n\n    free(arr);  /* Free memory after usage */\n}\n\n/* Wrong */\nvoid\nmy_func(size_t size) {\n    int32_t arr[size];  /* Wrong, do not use VLA */\n}\n```\n\n- Always compare variable against zero, except if it is treated as `boolean` type\n- Never compare `boolean-treated` variables against zero or one. Use NOT (`!`) instead\n```c\nsize_t length = 5;  /* Counter variable */\nuint8_t is_ok = 0;  /* Boolean-treated variable */\nif (length)         /* Wrong, length is not treated as boolean */\nif (length \u003e 0)     /* OK, length is treated as counter variable containing multi values, not only 0 or 1 */\nif (length == 0)    /* OK, length is treated as counter variable containing multi values, not only 0 or 1 */\n\nif (is_ok)          /* OK, variable is treated as boolean */\nif (!is_ok)         /* OK, -||- */\nif (is_ok == 1)     /* Wrong, never compare boolean variable against 1! */\nif (is_ok == 0)     /* Wrong, use ! for negative check */\n```\n\n- Always use `/* comment */` for comments, even for *single-line* comment\n- Always include check for `C++` with `extern` keyword in header file\n- Every function MUST include *doxygen-enabled* comment, even if function is `static`\n- Use English names/text for functions, variables, comments\n- Use *lowercase* characters for variables\n- Use *underscore* if variable contains multiple names, eg. `force_redraw`. Do not use `forceRedraw`\n- Never cast function returning `void *`, eg. `uint8_t* ptr = (uint8_t *)func_returning_void_ptr();` as `void *` is safely promoted to any other pointer type\n    - Use `uint8_t* ptr = func_returning_void_ptr();` instead\n- Always use `\u003c` and `\u003e` for C Standard Library include files, eg. `#include \u003cstdlib.h\u003e`\n- Always use `\"\"` for custom libraries, eg. `#include \"my_library.h\"`\n- When casting to pointer type, always align asterisk to type, eg. `uint8_t* t = (uint8_t*)var_width_diff_type`\n- Always respect code style already used in project or library\n\n## Comments\n\n- Comments starting with `//` are not allowed. Always use `/* comment */`, even for single-line comment\n```c\n//This is comment (wrong)\n/* This is comment (ok) */\n```\n\n- For multi-line comments use `space+asterisk` for every line\n```c\n/*\n * This is multi-line comments,\n * written in 2 lines (ok)\n */\n\n/**\n * Wrong, use double-asterisk only for doxygen documentation\n */\n\n/*\n* Single line comment without space before asterisk (wrong)\n*/\n\n/*\n * Single line comment in multi-line configuration (wrong)\n */\n\n/* Single line comment (ok) */\n```\n\n- Use `12` indents (`12 * 4` spaces) offset when commenting. If statement is larger than `12` indents, make comment `4-spaces` aligned (examples below) to next available indent\n```c\nvoid\nmy_func(void) {\n    char a, b;\n\n    a = call_func_returning_char_a(a);          /* This is comment with 12*4 spaces indent from beginning of line */\n    b = call_func_returning_char_a_but_func_name_is_very_long(a);   /* This is comment, aligned to 4-spaces indent */\n}\n```\n\n## Functions\n\n- Every function which may have access from outside its module, MUST include function *prototype* (or *declaration*)\n- Function name MUST be lowercase, optionally separated with underscore `_` character\n```c\n/* OK */\nvoid my_func(void);\nvoid myfunc(void);\n\n/* Wrong */\nvoid MYFunc(void);\nvoid myFunc();\n```\n\n- When function returns pointer, align asterisk to return type\n```c\n/* OK */\nconst char* my_func(void);\nmy_struct_t* my_func(int32_t a, int32_t b);\n\n/* Wrong */\nconst char *my_func(void);\nmy_struct_t * my_func(void);\n```\n- Align all function prototypes (with the same/similar functionality) for better readability\n```c\n/* OK, function names aligned */\nvoid        set(int32_t a);\nmy_type_t   get(void);\nmy_ptr_t*   get_ptr(void);\n\n/* Wrong */\nvoid set(int32_t a);\nconst char * get(void);\n```\n\n- Function implementation MUST include return type and optional other keywords in separate line\n```c\n/* OK */\nint32_t\nfoo(void) {\n    return 0;\n}\n\n/* OK */\nstatic const char*\nget_string(void) {\n    return \"Hello world!\\r\\n\";\n}\n\n/* Wrong */\nint32_t foo(void) {\n    return 0;\n}\n```\n\n## Variables\n\n- Make variable name all lowercase with optional underscore `_` character\n```c\n/* OK */\nint32_t a;\nint32_t my_var;\nint32_t myvar;\n\n/* Wrong */\nint32_t A;\nint32_t myVar;\nint32_t MYVar;\n```\n\n- Group local variables together by `type`\n```c\nvoid\nfoo(void) {\n    int32_t a, b;   /* OK */\n    char a;\n    char b;         /* Wrong, char type already exists */\n}\n```\n\n- Do not declare variable after first executable statement\n```c\nvoid\nfoo(void) {\n    int32_t a;\n    a = bar();\n    int32_t b;      /* Wrong, there is already executable statement */\n}\n```\n\n- You may declare new variables inside next indent level\n```c\nint32_t a, b;\na = foo();\nif (a) {\n    int32_t c, d;   /* OK, c and d are in if-statement scope */\n    c = foo();\n    int32_t e;      /* Wrong, there was already executable statement inside block */\n}\n```\n\n- Declare pointer variables with asterisk aligned to type\n```c\n/* OK */\nchar* a;\n\n/* Wrong */\nchar *a;\nchar * a;\n```\n\n- When declaring multiple pointer variables, you may declare them with asterisk aligned to variable name\n```c\n/* OK */\nchar *p, *n;\n```\n\n## Structures, enumerations, typedefs\n\n- Structure or enumeration name MUST be lowercase with optional underscore `_` character between words\n- Structure or enumeration may contain `typedef` keyword\n- All structure members MUST be lowercase\n- All enumeration members SHOULD be uppercase\n- Structure/enumeration MUST follow doxygen documentation syntax\n\nWhen structure is declared, it may use one of `3` different options:\n\n1. When structure is declared with *name only*, it *MUST not* contain `_t` suffix after its name.\n```c\nstruct struct_name {\n    char* a;\n    char b;\n};\n```\n2. When structure is declared with *typedef only*, it *has to* contain `_t` suffix after its name.\n```c\ntypedef struct {\n    char* a;\n    char b;\n} struct_name_t;\n```\n3. When structure is declared with *name and typedef*, it *MUST NOT* contain `_t` for basic name and it *MUST* contain `_t` suffix after its name for typedef part.\n```c\ntypedef struct struct_name {    /* No _t */\n    char* a;\n    char b;\n    char c;\n} struct_name_t;    /* _t */\n```\n\nExamples of bad declarations and their suggested corrections\n```c\n/* a and b MUST be separated to 2 lines */\n/* Name of structure with typedef MUST include _t suffix */\ntypedef struct {\n    int32_t a, b;\n} a;\n\n/* Corrected version */\ntypedef struct {\n    int32_t a;\n    int32_t b;\n} a_t;\n\n/* Wrong name, it MUST not include _t suffix */\nstruct name_t {\n    int32_t a;\n    int32_t b;\n};\n\n/* Wrong parameters, MUST be all uppercase */\ntypedef enum {\n    MY_ENUM_TESTA,\n    my_enum_testb,\n} my_enum_t;\n```\n\n- When initializing structure on declaration, use `C99` initialization style\n```c\n/* OK */\na_t a = {\n    .a = 4,\n    .b = 5,\n};\n\n/* Wrong */\na_t a = {1, 2};\n```\n\n- When new typedef is introduced for function handles, use `_fn` suffix\n```c\n/* Function accepts 2 parameters and returns uint8_t */\n/* Name of typedef has `_fn` suffix */\ntypedef uint8_t (*my_func_typedef_fn)(uint8_t p1, const char* p2);\n```\n\n## Compound statements\n\n- Every compound statement MUST include opening and closing curly bracket, even if it includes only `1` nested statement\n- Every compound statement MUST include single indent; when nesting statements, include `1` indent size for each nest\n```c\n/* OK */\nif (c) {\n    do_a();\n} else {\n    do_b();\n}\n\n/* Wrong */\nif (c)\n    do_a();\nelse\n    do_b();\n\n/* Wrong */\nif (c) do_a();\nelse do_b();\n```\n\n- In case of `if` or `if-else-if` statement, `else` MUST be in the same line as closing bracket of first statement\n```c\n/* OK */\nif (a) {\n\n} else if (b) {\n\n} else {\n\n}\n\n/* Wrong */\nif (a) {\n\n}\nelse {\n\n}\n\n/* Wrong */\nif (a) {\n\n}\nelse\n{\n\n}\n```\n\n- In case of `do-while` statement, `while` part MUST be in the same line as closing bracket of `do` part\n```c\n/* OK */\ndo {\n    int32_t a;\n    a = do_a();\n    do_b(a);\n} while (check());\n\n/* Wrong */\ndo\n{\n/* ... */\n} while (check());\n\n/* Wrong */\ndo {\n/* ... */\n}\nwhile (check());\n```\n\n- Indentation is REQUIRED for every opening bracket\n```c\nif (a) {\n    do_a();\n} else {\n    do_b();\n    if (c) {\n        do_c();\n    }\n}\n```\n\n- Compound statement MUST include curly brackets, even in the case of a single statement. Examples below show bad practices\n```c\nif (a) do_b();\nelse do_c();\n\nif (a) do_a(); else do_b();\n```\n\n- Empty `while`, `do-while` or `for` loops MUST include brackets\n```c\n/* OK */\nwhile (is_register_bit_set()) {}\n\n/* Wrong */\nwhile (is_register_bit_set());\nwhile (is_register_bit_set()) { }\nwhile (is_register_bit_set()) {\n}\n```\n\n- If `while` (or `for`, `do-while`, etc) is empty (it can be the case in embedded programming), use empty single-line brackets\n```c\n/* Wait for bit to be set in embedded hardware unit */\nvolatile uint32_t* addr = HW_PERIPH_REGISTER_ADDR;\n\n/* Wait bit 13 to be ready */\nwhile (*addr \u0026 (1 \u003c\u003c 13)) {}        /* OK, empty loop contains no spaces inside curly brackets */\nwhile (*addr \u0026 (1 \u003c\u003c 13)) { }       /* Wrong */\nwhile (*addr \u0026 (1 \u003c\u003c 13)) {         /* Wrong */\n\n}\nwhile (*addr \u0026 (1 \u003c\u003c 13));          /* Wrong, curly brackets are missing. Can lead to compiler warnings or unintentional bugs */\n```\n- Always prefer using loops in this order: `for`, `do-while`, `while`\n- Avoid incrementing variables inside loop block if possible, see examples\n\n```c\n/* Not recommended */\nint32_t a = 0;\nwhile (a \u003c 10) {\n    .\n    ..\n    ...\n    ++a;\n}\n\n/* Better */\nfor (size_t a = 0; a \u003c 10; ++a) {\n\n}\n\n/* Better, if inc may not happen in every cycle */\nfor (size_t a = 0; a \u003c 10; ) {\n    if (...) {\n        ++a;\n    }\n}\n```\n\n- Inline `if` statement MAY be used only for assignment or function call operations\n```c\n/* OK */\nint a = condition ? if_yes : if_no; /* Assignment */\nfunc_call(condition ? if_yes : if_no); /* Function call */\nswitch (condition ? if_yes : if_no) {...}   /* OK */\n\n/* Wrong, this code is not well maintenable */\ncondition ? call_to_function_a() : call_to_function_b();\n\n/* Rework to have better program flow */\nif (condition) {\n    call_to_function_a();\n} else {\n    call_to_function_b();\n}\n```\n\n### Switch statement\n\n- Add *single indent* for every `case` statement\n- Use additional *single indent* for `break` statement in each `case` or `default` statement\n```c\n/* OK, every case has single indent */\n/* OK, every break has additional indent */\nswitch (check()) {\n    case 0:\n        do_a();\n        break;\n    case 1:\n        do_b();\n        break;\n    default:\n        break;\n}\n\n/* Wrong, case indent missing */\nswitch (check()) {\ncase 0:\n    do_a();\n    break;\ncase 1:\n    do_b();\n    break;\ndefault:\n    break;\n}\n\n/* Wrong */\nswitch (check()) {\n    case 0:\n        do_a();\n    break;      /* Wrong, break MUST have indent as it is under case */\n    case 1:\n    do_b();     /* Wrong, indent under case is missing */\n    break;\n    default:\n        break;\n}\n```\n\n- Always include `default` statement\n```c\n/* OK */\nswitch (var) {\n    case 0:\n        do_job();\n        break;\n    default:\n        break;\n}\n\n/* Wrong, default is missing */\nswitch (var) {\n    case 0:\n        do_job();\n        break;\n}\n```\n\n- If local variables are REQUIRED, use curly brackets and put `break` statement inside.\n    - Put opening curly bracket in the same line as `case` statement\n```c\nswitch (a) {\n    /* OK */\n    case 0: {\n        int32_t a, b;\n        char c;\n        a = 5;\n        /* ... */\n        break;\n    }\n\n    /* Wrong */\n    case 1:\n    {\n        int32_t a;\n        break;\n    }\n\n    /* Wrong, break shall be inside */\n    case 2: {\n        int32_t a;\n    }\n    break;\n}\n```\n\n## Macros and preprocessor directives\n\n- Always use macros instead of literal constants, especially for numbers\n- All macros MUST be fully uppercase, with optional underscore `_` character, except if they are clearly marked as function which may be in the future replaced with regular function syntax\n```c\n/* OK */\n#define SQUARE(x)         ((x) * (x))\n\n/* Wrong */\n#define square(x)           ((x) * (x))\n```\n\n- Always protect input parameters with parentheses\n```c\n/* OK */\n#define MIN(x, y)           ((x) \u003c (y) ? (x) : (y))\n\n/* Wrong */\n#define MIN(x, y)           x \u003c y ? x : y\n```\n\n- Always protect final macro evaluation with parenthesis\n```c\n/* Wrong */\n#define MIN(x, y)           (x) \u003c (y) ? (x) : (y)\n#define SUM(x, y)           (x) + (y)\n\n/* Imagine result of this equation using wrong SUM implementation */\nint32_t x = 5 * SUM(3, 4);  /* Expected result is 5 * 7 = 35 */\nint32_t x = 5 * (3) + (4);  /* It is evaluated to this, final result = 19 which is not what we expect */\n\n/* Correct implementation */\n#define MIN(x, y)           ((x) \u003c (y) ? (x) : (y))\n#define SUM(x, y)           ((x) + (y))\n```\n\n- When macro uses multiple statements, protect these using `do {} while (0)` statement\n```c\ntypedef struct {\n    int32_t px, py;\n} point_t;\npoint_t p;                  /* Define new point */\n\n/* Wrong implementation */\n\n/* Define macro to set point */\n#define SET_POINT(p, x, y)  (p)-\u003epx = (x); (p)-\u003epy = (y)    /* 2 statements. Last one should not implement semicolon */\n\nSET_POINT(\u0026p, 3, 4);        /* Set point to position 3, 4. This evaluates to... */\n(\u0026p)-\u003epx = (3); (\u0026p)-\u003epy = (4); /* ... to this. In this example this is not a problem. */\n\n/* Consider this ugly code, however it is valid by C standard (not recommended) */\nif (a)                      /* If a is true */\n    if (b)                  /* If b is true */\n        SET_POINT(\u0026p, 3, 4);/* Set point to x = 3, y = 4 */\n    else\n        SET_POINT(\u0026p, 5, 6);/* Set point to x = 5, y = 6 */\n\n/* Evaluates to code below. Do you see the problem? */\nif (a)\n    if (b)\n        (\u0026p)-\u003epx = (3); (\u0026p)-\u003epy = (4);\n    else\n        (\u0026p)-\u003epx = (5); (\u0026p)-\u003epy = (6);\n\n/* Or if we rewrite it a little */\nif (a)\n    if (b)\n        (\u0026p)-\u003epx = (3);\n        (\u0026p)-\u003epy = (4);\n    else\n        (\u0026p)-\u003epx = (5);\n        (\u0026p)-\u003epy = (6);\n\n/*\n * Ask yourself a question: To which `if` statement does the `else` keyword belong?\n *\n * Based on first part of code, answer is straight-forward. To inner `if` statement when we check `b` condition\n * Actual answer: Compilation error as `else` belongs nowhere\n */\n\n/* Better and correct implementation of macro */\n#define SET_POINT(p, x, y)  do { (p)-\u003epx = (x); (p)-\u003epy = (y); } while (0)    /* 2 statements. No semicolon after while loop */\n/* Or even better */\n#define SET_POINT(p, x, y)  do {    \\   /* Backslash indicates statement continues in new line */\n    (p)-\u003epx = (x);                  \\\n    (p)-\u003epy = (y);                  \\\n} while (0)                             /* 2 statements. No semicolon after while loop */\n\n/* Now original code evaluates to */\nif (a)\n    if (b)\n        do { (\u0026p)-\u003epx = (3); (\u0026p)-\u003epy = (4); } while (0);\n    else\n        do { (\u0026p)-\u003epx = (5); (\u0026p)-\u003epy = (6); } while (0);\n\n/* Every part of `if` or `else` contains only `1` inner statement (do-while), hence this is valid evaluation */\n\n/* To make code perfect, use brackets for every if-ifelse-else statements */\nif (a) {                    /* If a is true */\n    if (b) {                /* If b is true */\n        SET_POINT(\u0026p, 3, 4);/* Set point to x = 3, y = 4 */\n    } else {\n        SET_POINT(\u0026p, 5, 6);/* Set point to x = 5, y = 6 */\n    }\n}\n```\n\n- Avoid using `#ifdef` or `#ifndef`. Use `defined()` or `!defined()` instead\n```c\n#ifdef XYZ\n/* do something */\n#endif /* XYZ */\n```\n\n- Always document `if/elif/else/endif` statements\n```c\n/* OK */\n#if defined(XYZ)\n/* Do if XYZ defined */\n#else /* defined(XYZ) */\n/* Do if XYZ not defined */\n#endif /* !defined(XYZ) */\n\n/* Wrong */\n#if defined(XYZ)\n/* Do if XYZ defined */\n#else\n/* Do if XYZ not defined */\n#endif\n```\n\n- Do not indent sub statements inside `#if` statement\n```c\n/* OK */\n#if defined(XYZ)\n#if defined(ABC)\n/* do when ABC defined */\n#endif /* defined(ABC) */\n#else /* defined(XYZ) */\n/* Do when XYZ not defined */\n#endif /* !defined(XYZ) */\n\n/* Wrong */\n#if defined(XYZ)\n    #if defined(ABC)\n        /* do when ABC defined */\n    #endif /* defined(ABC) */\n#else /* defined(XYZ) */\n    /* Do when XYZ not defined */\n#endif /* !defined(XYZ) */\n```\n\n## Documentation\n\nDocumented code allows doxygen to parse and generate html/pdf/latex output, thus it is very important to do it properly at an early stage of the project.\n\n- Use doxygen-enabled documentation style for `variables`, `functions` and `structures/enumerations`\n- Always use `\\` for doxygen, do not use `@`\n- Always use `5x4` spaces (`5` tabs) offset from beginning of line for text\n```c\n/**\n * \\brief           Holds pointer to first entry in linked list\n *                  Beginning of this text is 5 tabs (20 spaces) from beginning of line\n */\nstatic\ntype_t* list;\n```\n\n- Every structure/enumeration member MUST include documentation\n- Align start of comments between different structure members to the same column\n```c\n/**\n * \\brief           This is point struct\n * \\note            This structure is used to calculate all point\n *                      related stuff\n */\ntypedef struct {\n    int32_t x;                                  /*!\u003c Point X coordinate */\n    int32_t y;                                  /*!\u003c Point Y coordinate */\n    int32_t size;                               /*!\u003c Point size.\n                                                    Since comment is very big,\n                                                    you may go to next line */\n} point_t;\n\n/**\n * \\brief           Point color enumeration\n */\ntypedef enum {\n    COLOR_RED,                                  /*!\u003c Red color */\n    COLOR_GREEN,                                /*!\u003c Green color */\n    COLOR_BLUE,                                 /*!\u003c Blue color */\n} point_color_t;\n```\n\n- Documentation for functions MUST be written in function implementation (source file usually)\n- Function MUST include `brief` and all parameters documentation\n- Every parameter MUST be noted if it is `in` or `out` for *input* and *output* respectively\n- Function MUST include `return` parameter if it returns something. This does not apply for `void` functions\n- Function can include other doxygen keywords, such as `note` or `warning`\n- Use colon `:` between parameter name and its description\n```c\n/**\n * \\brief           Sum `2` numbers\n * \\param[in]       a: First number\n * \\param[in]       b: Second number\n * \\return          Sum of input values\n */\nint32_t\nsum(int32_t a, int32_t b) {\n    return a + b;\n}\n\n/**\n * \\brief           Sum `2` numbers and write it to pointer\n * \\note            This function does not return value, it stores it to pointer instead\n * \\param[in]       a: First number\n * \\param[in]       b: Second number\n * \\param[out]      result: Output variable used to save result\n */\nvoid\nvoid_sum(int32_t a, int32_t b, int32_t* result) {\n    *result = a + b;\n}\n```\n\n- If function returns member of enumeration, use `ref` keyword to specify which one\n```c\n/**\n * \\brief           My enumeration\n */\ntypedef enum {\n    MY_ERR,                                     /*!\u003c Error value */\n    MY_OK                                       /*!\u003c OK value */\n} my_enum_t;\n\n/**\n * \\brief           Check some value\n * \\return          \\ref MY_OK on success, member of \\ref my_enum_t otherwise\n */\nmy_enum_t\ncheck_value(void) {\n    return MY_OK;\n}\n```\n\n- Use notation (\\`NULL\\` =\u003e `NULL`) for constants or numbers\n```c\n/**\n * \\brief           Get data from input array\n * \\param[in]       in: Input data\n * \\return          Pointer to output data on success, `NULL` otherwise\n */\nconst void *\nget_data(const void* in) {\n    return in;\n}\n```\n\n- Documentation for macros MUST include `hideinitializer` doxygen command\n```c\n/**\n * \\brief           Get minimal value between `x` and `y`\n * \\param[in]       x: First value\n * \\param[in]       y: Second value\n * \\return          Minimal value between `x` and `y`\n * \\hideinitializer\n */\n#define MIN(x, y)       ((x) \u003c (y) ? (x) : (y))\n```\n\n## Header/source files\n\n- Leave single empty line at the end of file\n- Every file MUST include doxygen annotation for `file` and `brief` description followed by empty line (when using doxygen)\n```c\n/**\n * \\file            template.h\n * \\brief           Template include file\n */\n                    /* Here is empty line */\n```\n\n- Every file (*header* or *source*) MUST include license (opening comment includes single asterisk as this MUST be ignored by doxygen)\n- Use the same license as already used by project/library\n```c\n/**\n * \\file            template.h\n * \\brief           Template include file\n */\n\n/*\n * Copyright (c) year FirstName LASTNAME\n *\n * Permission is hereby granted, free of charge, to any person\n * obtaining a copy of this software and associated documentation\n * files (the \"Software\"), to deal in the Software without restriction,\n * including without limitation the rights to use, copy, modify, merge,\n * publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so,\n * subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE\n * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n *\n * This file is part of library_name.\n *\n * Author:          FirstName LASTNAME \u003coptional_email@example.com\u003e\n */\n```\n\n- Header file MUST include guard `#ifndef`\n- Header file MUST include `C++` check\n- Include external header files outside `C++` check\n- Include external header files with STL C files first followed by application custom files\n- Header file MUST include only every other header file in order to compile correctly, but not more (.c should include the rest if REQUIRED)\n- Header file MUST only expose module public variables/types/functions\n- Use `extern` for global module variables in header file, define them in source file later\n```\n/* file.h ... */\n#ifndef ...\n\nextern int32_t my_variable; /* This is global variable declaration in header */\n\n#endif\n\n/* file.c ... */\nint32_t my_variable;        /* Actually defined in source */\n```\n- Never include `.c` files in another `.c` file\n- `.c` file should first include corresponding `.h` file, later others, unless otherwise explicitly necessary\n- Do not include module private declarations in header file\n\n- Header file example (no license for sake of an example)\n```c\n/* License comes here */\n#ifndef TEMPLATE_HDR_H\n#define TEMPLATE_HDR_H\n\n/* Include headers */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n/* File content here */\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n\n#endif /* TEMPLATE_HDR_H */\n```\n\n## Clang format integration\n\nRepository comes with always-up-to-date `.clang-format` file, an input configuration\nfor `clang-format` tool. It can be seamlessly integrated with most of latest techno\nIDEs, including VSCode. Formatting then happens on the spot on each file save.\n\nhttps://code.visualstudio.com/docs/cpp/cpp-ide#_code-formatting\n\n## Artistic style configuration\n\n[AStyle](http://astyle.sourceforge.net/) is a great piece of software that can\nhelp with formatting the code based on input configuration.\n\nThis repository contains `astyle-code-format.cfg` file which can be used with `AStyle` software.\n\n```\nastyle --options=\"astyle-code-format.cfg\" \"input_path/*.c,*.h\" \"input_path2/*.c,*.h\"\n```\n\n\u003e Artistic style configuration is obsolete and no longer updated\n\n## Eclipse formatter\n\nRepository contains `eclipse-ext-kr-format.xml` file that can be used with\neclipse-based toolchains to set formatter options.\n\nIt is based on K\u0026R formatter with modifications to respect above rules.\nYou can import it within eclipse settings, `Preferences -\u003e LANGUAGE -\u003e Code Style -\u003e Formatter` tab.\n","funding_links":["paypal.me/tilz0R"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmajerle%2Fc-code-style","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmajerle%2Fc-code-style","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmajerle%2Fc-code-style/lists"}