1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
/*!
* \page cfu-coding-guidelines-page crystal-facet-uml coding guidelines
*
* \image html crystal_facet_uml.png
* \image latex crystal_facet_uml.pdf "" width=3cm
*
* \section cfu-modules Software Modules
*
* The software consists of several modules.
* \n Some are external modules and may therefore not follow the rules listed below.
* \n The others belong to the crystal-facet-uml application.
*
* \subsection cfu-folder-structure Folder Structure
*
* Each module consists of the following top-level folders:
* - include/
* \n contains all public interfaces of the module
* \n as well as private interfaces+inline functions on which the public interfaces depend.
* - source/
* \n contains all module-internal interfaces, source codes and resources.
* - test/
* \n contains test cases for that software module
* .
*
* \subsection cfu-namespaces Namespaces
*
* Since ANSI-C 99 does not provide namespaces, all file names, functions, types, enumeration-constants shall have a prefix.
* \n If a module has sub-modules, these may have different prefixes.
*
* \subsection cfu-files Files
*
* - Every compilation unit file (.c) shall have one header file (.h) with the same name.
* - Every header file (.h) may have one inline file (.inl) with the same name.
* \n This inline file contains inline definitions of functions.
* .
*
* \subsection cfu-coupling Loose Coupling
* Independant software modules shall provide loose coupling and depencendy injection.
* This is especially important when lower-layer modules broadcast messages to e.g. upper layer modules.
* To allow loose coupling, glib signals shall be emitted.
* Dependencies between these modules can be injected from outside.
*
* Within a software module, other ways of messaging is preferred, e.g. listener concepts,
* where the compiler can check types of parameters (of function pointers).
*
* \section cfu-classes Classes and Objects
*
* All files shall follow object-oriented design patterns in the following way:
* - Each header file declares one main type, a struct, with the same name as the file (postfixed by _t).
* \n This struct is used like a class.
* .
* Even functions that do not share a data-object shall declare such a class-like struct.
* Besides conformity of style, this guideline makes dependencies between classes explicit.
*
* \subsection cfu-attributes Attributes
*
* - All struct elements are private and shall be accessed via "_get_", "_is_" and "_set_" functions.
* \n To achieve good runtime-performance, these may be declared as "static inline".
* - Attributes that have a shorter lifetime than the parent object shall be prefixed by "temp_".
* - Only for constant initialization, attributes may be used directly, e.g. "const point_t pnt = {.x=2, .y=5};"
* .
*
* \subsection cfu-methods Methods
*
* - All function names are pre-fixed by the main type name.
* - The first parameter of each function is a pointer to an instance of the main type.
* \n The name of the first parameter is "this_".
* \n This first parameter must not be NULL and needs not be checked for NULL.
* - Functions that shall not be accessed from outside are in-fixed by "_private_".
* - Functions that expose pointers or accessors to internal data shall be post-fixed by "_ptr".
* \n If the exposed member is const, "_const" may alternatively be used as postfix.
* \n Care needs to be taken when changing internal data from outside
* and when reading data from outside while it may be changed from inside.
* - All functions may assume (unless explicitly documented) that they are only called
* \n after an init call and
* \n before a destroy call
* .
*
* \subsection cfu-create-destroy Constructors, Copy-Constructors, Move-Constructors and Destructors
*
* Similar to classes, at least one constructor and a destructor shall be provided.
* - Any constructor starts with the type-name and "_init" as prefix.
* \n A constructor shall initialize the struct in a way that all functions can be called without causing harm.
* - Any copy/move constructor (if provided) starts with the type-name and "_copy"/"_move" as postfix.
* \n If no copy constructor is provided, the assignment "=" and memcpy may be used.
* - The destructor starts with the type-name and ends with "_destroy".
* \n The destructor shall free any occupied resources (e.g. mutexes) and may set all references to
* external objects to NULL. It shall not do more: E.g. zero-ing the memory is not necessary.
* - Optionally, a "_reinit" de+constructor may be provided.
* \n This constructor shall re-initialize the struct that was already initialized before.
* - Optionally, "_replace"/"_replacemove" de+constructors may be provided for copying/moving objects into already initialized ones.
* \n This constructor shall re-initialize the struct that was already initialized before the copy/move of the provided object.
* - To facilitate static and/or constant initialization, uppercase TYPENAME() macros may map parameters to struct fields.
* \n Alternatively a function of name "<type-name>_new" may return a const object (not a pointer).
* .
*
* \subsection cfu-lifecycle Responsabilities for Creation and Destruction
*
* The general guideline is: who creates the object is responsible for destroying it.
*
* Special Considerations:
* - Functions may return objects only if the assignment via memcpy is a valid move-operation.
* The caller is responsible for destroying it.
* \n Rationale: The caller will most likely do an assignment like result_object=function(x);
* Only result_object can be destroyed by the caller, not the copy on the stack.
* - Functions may accept object-parameters (non-pointer) only if the assignment via memcpy is a valid copy-operation.
* \n Rationale: The caller will do an assignment like function(object_parameter); which produces a copy.
* Note that the caller is still responsible to destroy object_parameter and the callee to destroy the copy.
* - Functions may define memory locations for result-objects as "out_"-parameter. The caller shall pre-initialize these.
* \n Rationale: This allows to stick to the followin rule: Who creates an object is responsible for destroying it.
* - Arrays: Objects in arrays shall be destroyed as all other objects.
* - Exceptions shall be documented.
* - Avoid using NULL pointers, prefer using pointers to void objects.
* \n Rationale: This avoids segmentation faults in case of not checking for NULL, software gets more robust.
* .
*
* \subsection cfu-interfaces Implementing Abstract Interfaces
*
* How to define an abstract interface, implement it and then pass an instance of the abstract interface to clients,
* see universal_output_stream_t.
* \see universal_output_stream_t
* \see universal_output_stream_if_t
* \see universal_file_output_stream_t
* \see universal_memory_output_stream_t
*
* Note: there is also a more typesafe but less nice variant, \see io_element_writer_t .
*
* \section cfu-error Error Handling
*
* This section explains the detection of faults and anomalies, the propagation from detection to error handler and
* how an error handler shall react. Small anomalies shall be logged but need not be handled.
*
* \subsection cfu-error-handling Technical Concepts
*
* The following mechanisms shall be used for detection, propagation and handling of errors:
* - assert
* \n assert statements shall be used to validate that a function is called under appropriate conditions.
* \n assert statements shall be used to validate that a function returns values in the specified range.
* \n assert statements shall have no effect in NDEBUG mode, stop the program otherwise.
* - logging
* \n Faults and anomalies shall be logged when they occur.
* - fault injecttion
* \n In case a fault condition should be handled but cannot be provoked in the test environment with low efforts,
* the U8_FAULT_INJECT_COND() macro shall be inserted to allow unit-testing of the error handling.
* - error_codes
* \n The return parameter of a function shall be the error code. Futher return values shall be declared as *out_xy parmeter.
* \n Exception to this rule are helper and utility functions which do not report errors (only perform asserts)
* or where the return value contains the error e.g. by being invalid/void/empty (if such a state exists).
* - error handling
* \n Errors shall be reported to the user: in GUI mode, a message shall be shown in a window, in console mode, it shall be
* shown on std_err.
* \n If possible, the program shall continue running.
* .
*
* \section cfu-types Types (Declarations and Operators)
*
* Avoid implicit type conversions. Perform explicit type conversions instead.
*
* \subsection cfu-implicit-type-conversions Implicit Type Conversions
*
* Especially on arrays, one can get confused easily. While implicit type conversions are helpful as long as things are simple,
* one gets confused when looking at pointer-to-array-of-pointers and array-of-pointers-to-arrays.
*
* The term \c ((char*)buf)+len looks simple - but adds value \c len*sizeof(char) to the pointer \c buf and returns a pointer of type \c char*.
* These c-magic pointer-to-array conversions get confusing if types are more complicated than a simple char, e.g. \c ((char(*)[][7])buf)+len .
*
* In crystal-facet-uml, the preferred term is \c &((*((char(*)[])buf))[len]) - which is identical to \c ((char*)buf)+len.
* There is no magic: \c buf is cast to pointer-to-array \c char(*)[] . The pointer is dereferenced, the array-element \c len is selected,
* the address of that element is determined.
*
* Hints on C-Pitfalls:
* - An array is an array.
* \n to get a pointer onto the first element, call \c &(my_array[0]).
* \n to get a pointer onto the array, call \c &(my_array).
* - A pointer is a pointer.
* \n to get an array, cast the pointer-to-base-type to a pointer-to-array-of-base-type and dereference it: \c *((char(*)[])my_ptr)
* \n to get a function, dereference the pointer: *(my_func_ptr)
* \n avoid the + operator on pointers, dereference the pointer and access the array element instead: \c (*(array_ptr))[n]
* - A function is a function.
* \n to get a pointer to a function, write \c &(my_func).
* - A c-string is a char-array.
* \n to pass a c-string to a function, use a pointer on the array: \c &(my_string) of type \c char(*)[].
* .
*
* \section cfu-external-guidelines External Coding Guidelines
*
* To ensure high robustness and reproducability of the software, stick to MISRA-C rules wherever possible.
* In case you do not have a copy at hand, consider this similar set of rules:
* https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf
*
* \section cfu-coding-guidelines-apx Appendix
* \author Copyright 2016-2025 Andreas Warnke; Email-contact: cfu-at-andreaswarnke-dot-de
*/
|