Projet

Général

Profil

Wiki » Historique » Version 4

Patrice Nadeau, 2023-07-01 20:53

1 1 Patrice Nadeau
# Règles de codage C
2
3
Le langage C, version C99 (ISO/IEC 9899:1999) utilisé avec le compilateur [GCC](https://gcc.gnu.org/).
4
5
> `gcc` n'est pas entièrement compatible avec le standard C99 (<https://gcc.gnu.org/c99status.html>).
6
7
---
8
{{toc}}
9
10
## Style
11
12 4 Patrice Nadeau
Le code DOIT être dans le style [K&R](https://fr.wikipedia.org/wiki/Style_d%27indentation#Style_K&R) avec la variante *one true brace style* (1TBS):
13 1 Patrice Nadeau
* L’indentation est de 4 espaces
14
* Le « backslash » est utilisé pour les lignes de plus de 80 caractères
15
* Une instruction par ligne
16
* Une espace avant et après un opérateur sauf pour les opérateurs « [unaires](https://fr.wikipedia.org/wiki/Op%C3%A9ration_unaire) »
17
18
Justification :
19
* [K&R](https://fr.wikipedia.org/wiki/Style_d%27indentation#Style_K&R)
20
21
Exemple :
22
``` c
23 4 Patrice Nadeau
int fonction(void) {
24 1 Patrice Nadeau
    int x;
25
    if (var != 1) {
26
        x = x + 1;
27
        y++;
28
        printf("This is a long\
29
        line that should be splitted");
30 2 Patrice Nadeau
    } else {
31 1 Patrice Nadeau
        x--;
32 3 Patrice Nadeau
    };
33 1 Patrice Nadeau
    return 0;
34
}
35
```
36
37
### Langue
38
39
* Fonctions, variables et constantes DOIVENT être en anglais
40
* Commentaires et documentation DOIVENT être en français
41
42
### Copyright
43
44
[BSD 2 clauses (FreeBSD)](https://opensource.org/license/bsd-2-clause/)
45
46
Copier dans un fichier `LICENSE.txt`
47
48
### Doxygen
49
Logiciel [Doxygen](https://www.doxygen.nl/) utilisé pour générer la documentation à partir de commentaires spécialement formatés.
50
51
Chaque objet (fonctions, variables, etc.) DOIT être commenté/documenté : 
52
* Dans le format [Javadoc](https://www.doxygen.nl/manual/docblocks.html) (/** */)
53
* Avant sa déclaration
54
55
Exemple :
56
``` c
57
/**
58
 * @brief Universal answer
59
*/
60
const int ANSWER 42;
61
```
62
63
## Fichiers
64
Le nom des fichiers DOIT être composé de la manière suivante :
65
* En minuscule
66
* 8 caractères maximum
67
* L'extension est 
68
    * `.h` pour les fichiers d’entête
69
    * `.c` pour les fichiers sources
70
* Contient une section Doxygen « file »
71
* Les fichier d’entête contiennent en plus
72
    * Une section Doxygen « mainpage » 
73
    * Une définition macro DOIT être faite pour éviter de ré-inclure le fichier.
74
75
Exemple :
76
```c
77
#ifndef _test_h
78
#define _test_h
79
/**
80
 * @file : test.h
81
 * @brief Description
82
 * @version 0.00.01
83
 * @date 2023-02-26
84
 * @author Patrice Nadeau  <pnadeau@patricenadeau.com>
85
 * @copyright 2023 Patrice Nadeau
86
*/
87
88
/**
89
 * @mainpage lcd
90
 * @brief ATMEL AVR 8-bit C library
91
 * @author Patrice Nadeau <pnadeau@patricenadeau.com>
92
 * @version 0.0.02
93
 * @date 2023-03-27
94
 * @pre AVR supported (tested are in bold):
95
 * - ATmega88
96
 * - ATmega168
97
 * - @b ATmega328P
98
 * @copyright 
99
 * @include LICENSE.txt
100
*/
101
102
...
103
104
#endif /*_usart.h*/
105
```
106
107
## Commentaires
108
Les commentaires DOIVENT :
109
* Être de style « C »
110
* Précéder l’élément à documenté
111
* En minuscules et commencer par une majuscule
112
113
Exemple :
114
``` c
115
/* Une seule ligne... */
116
117
/*
118
* Sur
119
* plusieurs
120
* lignes
121
*/
122
```
123
124
## Convention de noms
125
126
* Les nom de fonction et de variable DOIVENT
127
    * Comporter au maximum **31** caractères
128
    * Être en minuscule
129
    * Être séparées par des traits de soulignement si comporte plusieurs mots
130
* Les nom de macro, constantes et #define DOIVENT
131
    * Comporter au maximum **31** caractères
132
    * Être en majuscule
133
    * Être séparées par des traits de soulignement si comporte plusieurs mots
134
135
Justification :
136
* Linux kernel coding style : <https://www.kernel.org/doc/html/v4.10/process/coding-style.html#naming>
137
* GNU Coding Standards <https://www.gnu.org/prep/standards/html_node/Writing-C.html#Writing-C>
138
* Embedded C Coding Standard : <https://barrgroup.com/embedded-systems/books/embedded-c-coding-standard>
139
140
## Déclarations locales
141
142
Une déclaration n’ayant qu’une visibilité locale DOIT :
143
* Être de classe `static`
144
145
Exemple:
146
``` c
147
/**
148
* @brief Local function
149
**/
150
static int local_func(void)
151
{
152
    ...
153
    return 0;
154
}
155
```
156
157
## Items déconseillés et retirés
158
159
Les fonctions et variables ne devant plus être utilisés, DOIVENT générer un message lors de la compilation (*-Wall*) si un appel est effectué.
160
* Les attributs`__attribute__((deprecated))` ou `__attribute__((unavailable))` DOIVENT être ajoutés à la déclaration.
161
* La documentation DOIT indiquer les substituts à utiliser.
162
163
Exemple :
164
``` c
165
/**
166
 * @brief OldFunction
167
 * @deprecated Use NewFunction instead
168
 * @since Version x.x.xx
169
 */
170
int OldFunction(void) __attribute__((deprecated));
171
172
/**
173
 * @brief OldFunction
174
 * @deprecated Use NewFunction instead
175
 * @since Version x.x.xx
176
 */
177
int OldFunction(void) __attribute__((unavailable));
178
```
179
180
## Constantes
181
182
Utilisé au lieu d’une macro quand le type ou la visibilité de la variable doit être définis.
183
184
DOIVENT être
185
* De classe _static_ ou _extern_ selon le besoin
186
187
Exemple :
188
189
``` c
190
/** 
191
 * @name List of constants
192
 * @brief
193
 */
194
/** @{ */
195
/** @brief The initialization string of the project */
196
static const char INIT_STR[6] = "POWER";
197
/** @brief Global const in the random library */
198
extern int RANDOM_MAX = 25;
199
/** @} */
200
201
/** @brief Constant */
202
const int ANSWER 42;
203
```
204
205
## Énumérations
206
207
DOIT être utilisée pour définir une série de valeurs.
208
209
Exemple :
210
```c
211
/**
212
 * @name List of STATUS values
213
 * @brief 
214
 * */
215
enum STATUS {
216
	/** @brief Everything is fine */
217
	STATUS_OK = 0,
218
	/** @brief Initialisation in progress */
219
	STATUS_INIT,
220
	/** @brief System halted */
221
	STATUS_HALTED
222
};
223
```
224
225
## Typedef
226
227
Format :
228
* En minuscule, suivie de **_t**
229
230
Exemple :
231
``` c
232
/** Type of structure in the ds1305 library */
233
typedef struct {
234
    /** @brief last two digits : &ge; 00, &le; 99 */
235
    uint8_t year;
236
    /** @brief 01 - 12 */
237
    uint8_t month;
238
    /** @brief 01 - 31 */
239
    uint8_t date;
240
    /** @brief 1 - 7 */
241
    uint8_t day;
242
    /** @brief 00 - 23 */
243
    uint8_t hours;
244
    /** @brief 00 - 59 */
245
    uint8_t minutes;
246
    /** @brief 00 - 59 */
247
    uint8_t seconds;
248
} ds1305_time_t;
249
```
250
251
## Variables
252
253
Exemple :
254
``` c
255
/** @brief Local variable */
256
static int ctr;
257
/** @brief Global variable */
258
int random_ctr;
259
```
260
261
## Structures
262
263
Format
264
* En minuscule, séparé par des «underscores» si nécessaire.
265
266
Exemple :
267
``` c
268
/**
269
* @brief Structure for a local menu
270
* @see MenuSelect
271
*/
272
struct menu {
273
/** @brief Character used for the item */
274
char choice;
275
/** @brief Description of the item */
276
char *item;
277
};
278
```
279
280
## Fonctions
281
282
283
Le nom DOIT être dans le format suivant : *Action***_***Item***_***Attribut*, où *Action* signifie :
284
* **set**, **clear**, **read** : écris ou lis un registre
285
* **read**, **write** : Lis ou écris dans un fichier
286
* **init** : Fonction d’initialisation
287
* **is** : Vérifie un état
288
289
Exceptions
290
* Les fonctions définies dans une librairie de bas niveau pour du matériel (« driver ») devraient utiliser le nom définis dans le « datasheet ».
291
292
Une fonction DEVRAIT retourner une valeur. 
293
* Dans le cas d'un « oui/non », la valeur DOIT être de type **int** avec les valeurs suivantes :
294
  * Succès : **0**
295
  * Erreur : **1**
296
* Type booléen (Librairie `<stdbool.h>`)
297
    * **true**
298
    * **false**
299
* Pointeur :
300
    * **NULL** : Erreur
301
    * Autre valeur  : adresse du pointeur
302
303
Justification :
304
* [AVR1000b](https://ww1.microchip.com/downloads/en/Appnotes/AVR1000b-Getting-Started-Writing-C-Code-for-AVR-DS90003262B.pdf)
305
306
Exemple :
307
308
``` c
309
/**
310
* @brief Check if a timer is set
311
* @param[in] nb Timer number. @n Possible values :
312
* − @arg @b TIMER_1
313
* − @arg @b TIMER_2
314
* @return
315
* @retval true Timer @e nb is set
316
* @retval false Timer @e nb is NOT set
317
* @par Example :
318
* Check if the timer is set
319
* @code
320
* ...
321
* result = is_timer_set();
322
* ...
323
* @endcode
324
* @pre init_timer
325
**/
326
327
static bool is_timer_set(uint8_t nb);
328
329
```
330
331
## Macros
332
333
Ne devrait servir que pour les directives du préprocesseur C.
334
335
### #include
336
337
Pour inclure d’autres fichier comme les fichiers entête.
338
> N’est pas documenté dans Doxygen.
339
340
### #ifdef / ifndef
341
342
Surtout utiliser pour des options de compilation sur différentes plateforme.
343
Utiliser une forme évitant les répétitions.
344
345
> N’est pas documenté dans Doxygen.
346
347
Exemple :
348
```c
349
const char BLUE =
350
  #if ENABLED(FEATURE_ONE)
351
    '1'
352
  #else
353
    '0'
354
  #endif
355
;
356
```
357
358
### Diagnostiques
359
360
Les macros `#warning` et `#error` sont utilisées pour afficher des avertissements (continue la compilation) ou des erreurs (arrête la compilation).
361
362
> Ne sont pas documentées dans Doxygen.
363
364
Exemple :
365
``` c
366
#ifndef usart_AVR
367
    #error "__FILE_NAME__ is not supported on this AVR !"
368
#endif
369
370
#ifndef __test__
371
    #warning "test is not defined !"
372
#endif
373
```
374
375
### Définitions
376
377
Un `#define` est utilisé pour remplacer une valeur au moment de la compilation
378
> Pour la définition d'une valeur « integer », un `enum` DOIT être utilisé.
379
380
Exemple :
381
``` c
382
/**
383
* @name Registers name
384
*/
385
/** @{ */ 
386
/** @brief USART1 */
387
#define USART1 REG1
388
/** @brief USART2 */
389
#define USART2 REG2
390
/** @} */
391
392
USART1 = 0x0F;
393
```
394
395
## Atmel AVR
396
397
Particularités pour les microcontrôleurs 8 bits AVR d’Atmel.
398
399
[Atmel AVR4027: Tips and Tricks to Optimize Your C Code for 8-bit AVR Microcontrollers](https://ww1.microchip.com/downloads/en/AppNotes/doc8453.pdf)
400
401
### Fichier d’en-têtes
402
403
```c
404
#include <avr/io.h>
405
```
406
407
### Macros
408
Liste des macros définies : 
409
* `F_CPU` : La fréquence utilisée par l'horloge (interne ou externe) du microcontrôleur
410
411
    > Les « fuses » doivent correspondent à la bonne source de l'horloge.
412
413
### Types
414
415
De nouveau type d'entier sont fournis avec la librairie `<stdint.h>`.
416
417
L'utilisation de ces types DOIT être utilisé afin d'exprimer le nombre de bit d'un objet.
418
419
### Progmem
420
Pour mettre des variables en lecture seule dans la section FLASH au lieu de SRAM avec `<avr/pgmspace.h>`.
421
> L’accès à ces variables est faite via les macros de la librairie.
422
423
Le nom de la variable DOIT être suivie de **_P**
424
425
Exemple :
426
```c
427
#include <avr/pgmspace.h>
428
...
429
/** @brief Variable en FLASH */
430
const int Variable1_P PROGMEM = 42;
431
```
432
433
### Fonction main
434
Un microcontrôleur AVR ne termine jamais la fonction `main`.
435
436
* Déclarer la fonction main avec l’attribut `noreturn`
437
* La boucle sans fin la plus optimisé est le `for (;;)`
438
439
Justification : [AVR035](https://ww1.microchip.com/downloads/en/AppNotes/doc1497.pdf)
440
441
Exemple :
442
```c
443
/** 
444
 * @brief Never ending loop
445
*/
446
void main(void) __attribute__((noreturn));
447
448
/* main function definition */
449
void main(void)
450
{
451
    ...
452
    /* never return */
453
    for (;;) {
454
    };
455
};
456
```
457
458
### Atomic
459
Opérations ne devant pas être interrompus comme charger un registre de 16 bits avec un registre de 8 bits.
460
461
La librairie `avr-libc` (util/atomic.h) fournit des macros permettant la gestion entre autre des interruptions.
462
463
Les instructions critiques sont insérées dans un `ATOMIC_BLOCK`.
464
465
Exemple :
466
```c
467
...
468
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
469
    ...
470
}
471
...
472
```