From 0d051ef3f081f05606bae9d798a6aac630db53f0 Mon Sep 17 00:00:00 2001 From: L-diy Date: Mon, 23 Oct 2023 21:09:32 +0200 Subject: [PATCH 1/3] Add a style guide --- style_guide.md | 531 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 531 insertions(+) create mode 100644 style_guide.md diff --git a/style_guide.md b/style_guide.md new file mode 100644 index 0000000..12bf495 --- /dev/null +++ b/style_guide.md @@ -0,0 +1,531 @@ +# C Style Guide and Rules + +## Table of contents +- [General rules](#general-rules) +- [Comments](#comments) +- [Functions](#functions) +- [Structures, enumerations, typedefs](#structures-enumerations-typedefs) +- [Compound statements](#compound-statements) +- [Macros and preprocessor directives](#macros-and-preprocessor-directives) +- [Documentation](#documentation) +- [Header/source files](#headersource-files) + +## Conventions used +MUST, MUST NOT, SHOULD, SHOULD NOT, MAY and OPTIONAL are used as described in [RFC 2119](https://tools.ietf.org/html/rfc2119). + +## General rules + +- Do not use tabs, use spaces instead +- Use `4` spaces per indent level +- Use `1` space between keyword and opening bracket +```c +// OK +if (condition) +while (condition) +for (init; condition; step) +do {} while (condition) + +// Wrong +if(condition) +while(condition) +for(init;condition;step) +do {} while(condition) +``` + +- Limit the line length to `120` characters, use `120` characters as a soft limit. +- Do not use space between function name and opening bracket +```c +int32_t a = sum(4, 3); // OK +int32_t a = sum (4, 3); // Wrong +``` + +- Use only lowercase characters for variables/functions/types with optional underscore `_` char +- Opening curly bracket is always at the same line as keyword (`for`, `while`, `do`, `switch`, `if`, ...) +```c +size_t i; +for (i = 0; i < 5; ++i) { // OK +} +for (i = 0; i < 5; ++i){ // Wrong +} +for (i = 0; i < 5; ++i) // Wrong +{ +} +``` + +- Use single space before and after comparison and assignment operators +```c +int32_t a; +a = 3 + 4; // OK +for (a = 0; a < 5; ++a) // OK +a=3+4; // Wrong +a = 3+4; // Wrong +for (a=0;a<5;++a) // Wrong +``` + +- Use single space after every comma +```c +func_name(5, 4); // OK +func_name(4,3); // Wrong +``` + +- Do not initialize `global` variables to any default value (or `NULL`), implement it in the dedicated `init` function (if REQUIRED). + +```c +static int32_t a; // OK +static int32_t b = 4; // Wrong + +void my_module_init(void) { + a = 0; + b = 4; +} +``` + +- Declare local variables in order + 1. Custom types, structures and enumerations + 2. Integer types + 3. Single/Double floating point +```c +int my_func(void) { + // 1 + my_struct_t my; + my_struct_ptr_t* p; + + // 2 + uint32_t a; + char h; + + // 3 + double d; + float f; +} +``` + +- Always declare local variables at the beginning of the block, before the first executable statement +- Always add trailing comma in the last element of structure (or its children) initialization. Unless the structure is very simple and short +```c +typedef struct { + int a, b; +} str_t; + +str_t s = { + .a = 1, + .b = 2, // Comma here +} + +// No trailing commas - only for small and simple structures +static const str_t y = {.a = 1, .b = 2}; +``` + +- Declare counter variables in `for` loop +```c +// OK +for (size_t i = 0; i < 10; ++i) + +// OK, if you need the counter variable later +size_t i; +for (i = 0; i < 10; ++i) { + if (...) { + break; + } +} +if (i == 10) { + +} + +// Wrong +size_t i; +for (i = 0; i < 10; ++i) ... +``` + +- Except `char`, `float` or `double`, always use types declared in `stdint.h` library, eg. `uint8_t` for `unsigned 8-bit`, etc. +- Never compare against `true`, eg. `if (check_func() == 1)`, use `if (check_func()) { ... }` +- Always compare pointers against `NULL` value +```c +void* ptr; + +// OK, compare against NULL +if (ptr == NULL || ptr != NULL) { + +} + +// Wrong +if (ptr || !ptr) { + +} +``` +- Always use `size_t` for length or size variables +- Always use `const` for a pointer if function should not modify memory pointed to by `pointer` +- Always use `const` for a function parameter or variable, if it should not be modified +```c + +/** + * When d could be modified, data pointed to by d could not be modified + */ +void my_func(const void* d) { + +} + +/** + * When d and data pointed to by d both could not be modified + */ +void my_func(const void* const d) { + +} + +/** + * When d should not be modified inside function, only data pointed to by d could be modified + */ +void my_func(void* const d) { + +} +``` + +- When a function may accept a pointer of any type, always use `void *`, do not use `uint8_t *` + - The function MUST take care of proper casting in implementation +- Always use brackets with `sizeof` operator +- Always compare variable against zero, except if it is treated as `boolean` type +- Never compare `boolean-treated` variables against zero or one. Use NOT (`!`) instead +```c +size_t length = 5; // Counter variable +uint8_t is_ok = 0; // Boolean-treated variable +if (length) // Wrong, length is not treated as boolean +if (is_ok) // OK, variable is treated as boolean +if (!is_ok) // OK +if (is_ok == 1) // Wrong, never compare boolean variable against 1! +if (is_ok == 0) // Wrong, use ! for negative check +``` + +- Every function MUST include *doxygen-enabled* comment, even if function is `static` +- Use English names/text for functions, variables, comments +- Use *lowercase* characters for variables +- Use *underscore* if variable contains multiple names, eg. `force_redraw`. Do not use `forceRedraw` +- Always use `<` and `>` for C Standard Library include files, eg. `#include ` +- Always use `""` for custom libraries, eg. `#include "my_library.h"` +- When casting to a pointer type, always align the asterisk to the type, eg. `uint8_t* t = (uint8_t*)var_width_diff_type` + +## Comments + +- Start every comment with capital letter, if possible +- Use `//` for single-line comments, start comment with single space +```c +// This is comment (ok) +/* This is comment (wrong) */ +``` + +- For multi-line comments use `space+asterisk` for every line +```c +/* + * This is multi-line comments, + * written in 2 lines (ok) + */ + +/** + * Wrong, use double-asterisk only for doxygen documentation + */ + +/* +* Single line comment without space before asterisk (wrong) +*/ + +/* + * Single line comment in multi-line configuration (wrong) + */ +``` + +- Make comments aligned to 4-spaces indent from the beginning of line, and aligned with the rest of the block +```c +void my_func(void) { + char a, b; + + a = call_func_returning_char_a(a); // This is a comment + b = call_func_returning_char_b_longer_func(a); // This is a comment, aligned to 4-spaces indent +} +``` + +## Functions + +- Every function which may have access from outside its module, must include function *prototype* (or *declaration*) in the header file +- Every function that is used only inside its module: + - Must be declared as `static` + - Must NOT include function prototype in the header file + - Must include function prototype in the source file +- Function name MUST be lowercase, optionally separated with underscore `_` character +```c +// OK +void my_func(void); +void myfunc(void); + +// Wrong +void MYFunc(void); +void myFunc(); +``` + +- When function returns pointer, align the asterisk to the return type +```c +// OK +const char* my_func(void); +my_struct_t* my_func(int32_t a, int32_t b); + +// Wrong +const char *my_func(void); +my_struct_t * my_func(void); +``` + +## Structures, enumerations, typedefs + +- Structure or enumeration name MUST be lowercase with optional underscore `_` character between words +- Structure or enumeration may contain `typedef` keyword +- All structure members SHOULD be lowercase +- All enumeration members MUST be uppercase + +When structure is declared, it may use one of `3` different options: + +1. When structure is declared with *name only*, it *MUST not* contain `_t` suffix after its name. +```c +struct struct_name { + char* a; + char b; +}; +``` +2. When structure is declared with *typedef only*, it *has to* contain `_t` suffix after its name. +```c +typedef struct { + char* a; + char b; +} struct_name_t; +``` +3. 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. +```c +typedef struct struct_name { + char* a; + char b; + char c; +} struct_name_t; +``` + +- When new typedef is introduced for function handles, use `_fn` suffix +```c +typedef uint8_t (*my_func_typedef_fn)(uint8_t p1, const char* p2); +``` + +## Compound statements + +- Every compound statement MUST include opening and closing curly bracket, even if it includes only `1` nested statement +- Every compound statement MUST include single indent; when nesting statements, include `1` indent size for each nest +```c +// OK +if (c) { + do_a(); +} else { + do_b(); +} + +// Wrong +if (c) + do_a(); +else + do_b(); + +// Wrong +if (c) do_a(); +else do_b(); +``` + +- In case of `if` or `if-else-if` statement, `else` MUST be in the same line as closing bracket of the first statement +```c +// OK +if (a) { + +} else if (b) { + +} else { + +} + +// Wrong +if (a) { + +} +else { + +} + +// Wrong +if (a) { + +} +else +{ + +} +``` + +- In case of `do-while` statement, `while` part MUST be in the same line as closing bracket of `do` part +```c +// OK +do { + /* ... */ +} while (check()); + +// Wrong +do +{ + /* ... */ +} while (check()); + +// Wrong +do { + /* ... */ +} +while (check()); +``` + +- Compound statement MUST include curly brackets, even in the case of a single statement. +- Avoid incrementing variables inside loop block if possible. + +### Switch statement +- Always include `default` statement +- Add *single indent* for every `case` statement +```c +// Ok +switch (check()) { + case 0: + do_a(); + break; + case 1: + do_b(); + break; + default: + break; +} + +// Wrong +switch (check()) { +case 0: // Wrong, case indent missing + do_a(); + break; // Wrong, break MUST have indent as it is under case + case 1: + do_b(); // Wrong, indent under case is missing + break; + default: + break; +} +``` + +## Macros and preprocessor directives + +- Always use macros instead of literal constants, especially for numbers +- Always protect input parameters with parentheses +- All macros MUST be fully uppercase, with optional underscore `_` character between words +```c +// OK +#define SQUARE(x) ((x) * (x)) + +// Wrong +#define square(x) ((x) * (x)) + +// Wrong +#define MIN(x, y) x < y ? x : y +``` + +- - Always document `if/elif/else/endif/ifdef/ifndef` statements +```c +#ifdef XYZ +/* do something */ +#endif /* XYZ */ +``` + +- Do not indent sub statements inside `#if` statement + +## Documentation + +- Use doxygen-enabled documentation style for `variables`, `functions` and `structures/enumerations` +- Always use `@` for doxygen, do not use `\` + +```c +/** + * @brief The main screen + */ +lv_obj_t * main_screen; +``` + +- Every structure/enumeration member MUST include documentation +```c +/** + * @brief Struct containing information about a wifi network + * @note The ssid is null terminated + */ +typedef struct { + char ssid[33]; + int8_t rssi; + ui_wifi_auth_mode_t auth_mode; +} ui_wifi_network_t; +``` + +- Documentation for functions used outside its module MUST be placed above function prototype in header file, that is, documentation that describes WHAT the function does. +- Documentation that describes HOW the function does it be placed with the function implementation. +- For functions that have only internal use, documentation MUST be placed with the function implementation. +- All functions MUST include a `brief` description +- Every parameter MUST be noted if it is `in` or `out` for *input* and *output* respectively +- Function MUST include `return` parameter if it returns something. This does not apply for `void` functions +- Function can include other doxygen keywords, such as `note` or `warning` +- If function returns member of enumeration, use `ref` keyword to specify which one +```c +/** + * @brief Parse and publish data from the meter data history endpoint + * + * @param[in] buf The buffer containing the JSON data + * @param[in] len The length of the JSON data + * @return @ref ESP_OK on success, member of @ref esp_err_t otherwise + */ +static esp_err_t parse_publish_meter_data_history(uint8_t *buf, uint32_t len) { + /* ... */ +} +``` + +## Header/source files + +- Leave a single empty line at the end of the file +- Every file MUST include doxygen annotation for `file` and `brief` description followed by empty line +```c +/** + * @file tsc2046.c + * @brief TSC2046 touch screen controller driver + */ + // Empty line +``` + +- Header file MUST include guard `#ifndef` +- Include external header files with STL C files first followed by application custom files +- Header file MUST include only every other header file to compile correctly, but not more (.c should include the rest if REQUIRED) +- Header file MUST only expose module public variables/types/functions +- Use `extern` for global module variables in header file, define them in source file later +``` +/* file.h ... */ +#ifndef ... + +extern int32_t my_variable; // This is global variable declaration in header + +#endif + +/* file.c ... */ +int32_t my_variable; // Actually defined in source +``` + +- Never include `.c` files in another `.c` file +- Do not include module private declarations in header file + +- Header file example +```c +/* License comes here */ +#ifndef TEMPLATE_HDR_H +#define TEMPLATE_HDR_H + +/* Include headers */ +#include +#include "my_custom_header.h" + +/* File content here */ + +#endif /* TEMPLATE_HDR_H */ +``` \ No newline at end of file From efff4ee8d1bc6d24a14b133eec35b719d43459bf Mon Sep 17 00:00:00 2001 From: Sani7 Date: Tue, 24 Oct 2023 13:43:49 +0200 Subject: [PATCH 2/3] fix c error in style guide --- style_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/style_guide.md b/style_guide.md index 12bf495..9c142b0 100644 --- a/style_guide.md +++ b/style_guide.md @@ -110,7 +110,7 @@ typedef struct { str_t s = { .a = 1, .b = 2, // Comma here -} +}; // No trailing commas - only for small and simple structures static const str_t y = {.a = 1, .b = 2}; From 997a1db06012d4867373d5c982f2d9dc9c7dfb6f Mon Sep 17 00:00:00 2001 From: L-diy Date: Tue, 24 Oct 2023 18:17:15 +0200 Subject: [PATCH 3/3] Add configuration files for code formatter tools --- .clang-format | 69 ++++++++++++++++ README.md | 22 +++++- eclipse_format.xml | 193 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 .clang-format create mode 100644 eclipse_format.xml diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a71906b --- /dev/null +++ b/.clang-format @@ -0,0 +1,69 @@ +--- +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: true +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +BinPackArguments: true +BinPackParameters: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: true +BreakStringLiterals: true +ColumnLimit: 120 +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +IncludeBlocks: Preserve +IncludeCategories: + - Regex: "^<(.*)>" + Priority: 0 + - Regex: ^"(.*)" + Priority: 1 + - Regex: "(.*)" + Priority: 2 +IncludeIsMainRegex: "(_test)?$" +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +MaxEmptyLinesToKeep: 1 +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never +UseCRLF: false +... diff --git a/README.md b/README.md index 569ecce..489eac3 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,29 @@ ## Used Libs, compiler and apps - lwip version 2.1.2 - - CubeIDE version 1.12.1 + - CubeIDE version 1.12.1 - Firmware Lib (stm32f7) 1.17.1 ## Tasks Maak per taak een apparte c en h file aan. De naam van de file is de naam van de taak. Zo kunnen we de code proper houden. - [taken_en_verdeling.md](Taken_en_Verdeling.md) \ No newline at end of file + [taken_en_verdeling.md](Taken_en_Verdeling.md) + +## Style Guide +To maintain a consistent and clean codebase, follow the [style guide](style_guide.md). This document provides detailed instructions on naming conventions, code structure, and commenting practices. + +Please read the [style_guide.md](style_guide.md) carefully before making contributions. + +### Editor Configuration + +To help you adhere to the style guide, use the provided configuration files for the code formatters in your code editor. +You can choose from the following options: + +- `.clang-format`: + - For [Visual Studio Code](https://code.visualstudio.com/docs/cpp/cpp-ide#_code-formatting) and [CLion](https://www.jetbrains.com/help/clion/clangformat-as-alternative-formatter.html#clion-support) users + - Or use the [clang-format](https://clang.llvm.org/docs/ClangFormat.html) tool directly + +- `eclipse_format.xml`: + - For Eclipse-based editors, including STM32CubeIDE. + - You can import it within eclipse settings, `Preferences -> LANGUAGE -> Code Style -> Formatter` tab. diff --git a/eclipse_format.xml b/eclipse_format.xml new file mode 100644 index 0000000..f3364ec --- /dev/null +++ b/eclipse_format.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +