Projet

Général

Profil

Wiki » Historique » Version 96

Patrice Nadeau, 2023-12-31 11:44

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