File: coding_guidelines.txt

package info (click to toggle)
crystal-facet-uml 1.63.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 21,640 kB
  • sloc: ansic: 109,610; xml: 3,085; makefile: 138; sh: 113
file content (193 lines) | stat: -rw-r--r-- 11,165 bytes parent folder | download
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
 */