Wiki » Historique » Révision 17
« Précédent |
Révision 17/170
(diff)
| Suivant »
Patrice Nadeau, 2023-07-08 18:44
Règles de codage C¶
Le langage C, version C99 (ISO/IEC 9899:1999) utilisé avec le compilateur GCC.
gcc
n'est pas entièrement compatible avec le standard C99 (https://gcc.gnu.org/c99status.html).
- Contenu
- Règles de codage C
Style¶
Le code DOIT :
- Être dans le style K&R avec la variante one true brace style (1TBS):
- L’indentation est de 4 espaces
- Le « backslash » est utilisé pour les lignes de plus de 80 caractères
- Une instruction par ligne
- Une espace avant et après un opérateur sauf pour les opérateurs « unaires »
Justification :
- K&R
- Prévient les erreurs lors d'ajout dans les boucles n'ayant qu'une instruction comme bloc
Exemple :
int fonction(void) {
int x;
if (var != 1) {
x = x + 1;
y++;
printf("This is a long\
line that should be splitted");
} else {
x--;
};
return 0;
}
Langue¶
- Fonctions, variables et constantes DOIVENT être en anglais
- Commentaires et documentation DOIVENT être en français
Copyright¶
Copier dans un fichier LICENSE.txt
Doxygen¶
Logiciel Doxygen utilisé pour générer la documentation à partir de commentaires spécialement formatés.
Chaque objet (fonctions, variables, etc.) DOIT être commenté/documenté :
- Dans le format Javadoc (/** */)
- Avant sa déclaration
- Les « décorations » sont faites avec la syntaxe Markdown
Exemple :
/**
* *italique*, **gras**
* `code en ligne`
*/
Fichiers¶
Le nom des fichiers DOIT être composé de la manière suivante :
- En minuscule
- 8 caractères maximum
- L'extension est
-
.h
pour les fichiers d’entête -
.c
pour les fichiers sources
-
- Contient une section Doxygen « file »
- Les fichier d’entête contiennent en plus
- Une section Doxygen « mainpage »
- Une définition macro DOIT être faite pour éviter de ré-inclure le fichier.
Exemple :
#ifndef _test_h
#define _test_h
/**
* @file : test.h
* @brief Description
* @version 0.00.01
* @date 2023-02-26
* @author Patrice Nadeau <pnadeau@patricenadeau.com>
* @copyright 2023 Patrice Nadeau
*/
/**
* @mainpage lcd
* @brief ATMEL AVR 8-bit C library
* @author Patrice Nadeau <pnadeau@patricenadeau.com>
* @version 0.0.02
* @date 2023-03-27
* @pre AVR supported (tested are in bold):
* - ATmega88
* - ATmega168
* - **ATmega328P**
* @copyright
* @include{doc} LICENSE.txt
*/
...
#endif /*_usart.h*/
Commentaires¶
Les commentaires DOIVENT :
- Être de style « C »
- Précéder l’élément à documenté
- En minuscules et commencer par une majuscule
Exemple :
/* Une seule ligne... */
/*
* Sur
* plusieurs
* lignes
*/
Convention de noms¶
- Les nom de fonction et de variable DOIVENT
- Comporter au maximum 31 caractères
- Être en minuscule
- Être séparées par des traits de soulignement si comporte plusieurs mots
- Les nom de macro, constantes et #define DOIVENT
- Comporter au maximum 31 caractères
- Être en majuscule
- Être séparées par des traits de soulignement si comporte plusieurs mots
Justification :
- Linux kernel coding style : https://www.kernel.org/doc/html/v4.10/process/coding-style.html#naming
- GNU Coding Standards https://www.gnu.org/prep/standards/html_node/Writing-C.html#Writing-C
- Embedded C Coding Standard : https://barrgroup.com/embedded-systems/books/embedded-c-coding-standard
Déclarations locales¶
Une déclaration n’ayant qu’une visibilité locale DOIT :
- Être de classe
static
Exemple:
/**
* @brief Local function
**/
static int local_func(void) {
...
return 0;
}
Items déconseillés et retirés¶
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é.
- Les attributs
__attribute__((deprecated))
ou__attribute__((unavailable))
DOIVENT être ajoutés à la déclaration. - La documentation DOIT indiquer les substituts à utiliser.
Exemple :
/**
* @brief OldFunction
* @deprecated Use NewFunction instead
* @since Version x.x.xx
*/
int OldFunction(void) __attribute__((deprecated));
/**
* @brief OldFunction
* @deprecated Use NewFunction instead
* @since Version x.x.xx
*/
int OldFunction(void) __attribute__((unavailable));
Constantes¶
Utilisé au lieu d’une macro quand le type ou la visibilité de la variable doit être définis.
DOIVENT être
- De classe static ou extern selon le besoin
Exemple :
/**
* @name List of constants
* @brief
*/
/** @{ */
/** @brief The initialization string of the project */
static const char INIT_STR[6] = "POWER";
/** @brief Global const in the random library */
extern int RANDOM_MAX = 25;
/** @} */
/** @brief Constant */
const int ANSWER 42;
Énumérations¶
DOIT être utilisée pour définir une série de valeurs.
Exemple :
/**
* @name List of STATUS values
* @brief
* */
enum STATUS {
/** @brief Everything is fine */
STATUS_OK = 0,
/** @brief Initialisation in progress */
STATUS_INIT,
/** @brief System halted */
STATUS_HALTED
};
Typedef¶
Format :
- En minuscule, suivie de _t
Exemple :
/** Type of structure in the ds1305 library */
typedef struct {
/** @brief last two digits : ≥ 00, ≤ 99 */
uint8_t year;
/** @brief 01 - 12 */
uint8_t month;
/** @brief 01 - 31 */
uint8_t date;
/** @brief 1 - 7 */
uint8_t day;
/** @brief 00 - 23 */
uint8_t hours;
/** @brief 00 - 59 */
uint8_t minutes;
/** @brief 00 - 59 */
uint8_t seconds;
} ds1305_time_t;
Variables¶
Exemple :
/** @brief Local variable */
static int ctr;
/** @brief Global variable */
int random_ctr;
Structures¶
Format
- En minuscule, séparé par des «underscores» si nécessaire.
Exemple :
/**
* @brief Structure for a local menu
* @see MenuSelect
*/
struct menu {
/** @brief Character used for the item */
char choice;
/** @brief Description of the item */
char *item;
};
Fonctions¶
Le nom DOIT être dans le format suivant : Action**Item**Attribut, où Action signifie :
- set, clear, read : écris ou lis un registre
- read, write : Lis ou écris dans un fichier
- init : Fonction d’initialisation
- is : Vérifie un état
Exceptions
- Les fonctions définies dans une librairie de bas niveau pour du matériel (« driver ») devraient utiliser le nom définis dans le « datasheet ».
Une fonction DEVRAIT retourner une valeur.
- Dans le cas d'un « oui/non », la valeur DOIT être de type int avec les valeurs suivantes :
- Succès : 0
- Erreur : 1
- Type booléen (Librairie
<stdbool.h>
)- true
- false
- Pointeur :
- NULL : Erreur
- Autre valeur : adresse du pointeur
Justification :
Exemple :
/**
* @brief Check if a timer is set
* @param[in] nb Timer number. @n Possible values :
* − @arg @b TIMER_1
* − @arg @b TIMER_2
* @return
* @retval true Timer @e nb is set
* @retval false Timer @e nb is NOT set
* @par Example :
* Check if the timer is set
* @code
* ...
* result = is_timer_set();
* ...
* @endcode
* @pre init_timer
**/
static bool is_timer_set(uint8_t nb);
Préprocesseur¶
Directives du préprocesseur gcc.
#include¶
Pour inclure d’autres fichier comme les fichiers entête.
N’est pas documenté dans Doxygen.
#ifdef / ifndef¶
Surtout utiliser pour des options de compilation sur différentes plateforme.
Utiliser une forme évitant les répétitions.
N’est pas documenté dans Doxygen.
Exemple :
const char BLUE =
#if ENABLED(FEATURE_ONE)
'1'
#else
'0'
#endif
;
Diagnostiques¶
Les macros #warning
et #error
sont utilisées pour afficher des avertissements (continue la compilation) ou des erreurs (arrête la compilation).
Ne sont pas documentées dans Doxygen.
Exemple :
#ifndef usart_AVR
#error "__FILE_NAME__ is not supported on this AVR !"
#endif
#ifndef __test__
#warning "test is not defined !"
#endif
Définitions¶
Un #define
est utilisé pour remplacer une valeur au moment de la compilation
Pour la définition d'une valeur « integer », un
enum
DOIT être utilisé.
Exemple :
/**
* @name Registers name
*/
/** @{ */
/** @brief USART1 */
#define USART1 REG1
/** @brief USART2 */
#define USART2 REG2
/** @} */
USART1 = 0x0F;
Atmel AVR¶
Particularités pour les microcontrôleurs 8 bits AVR d’Atmel.
Atmel AVR4027: Tips and Tricks to Optimize Your C Code for 8-bit AVR Microcontrollers
Fichier d’en-têtes¶
#include <avr/io.h>
Macros¶
Liste des macros définies :
-
F_CPU
: La fréquence utilisée par l'horloge (interne ou externe) du microcontrôleurLes « fuses » doivent correspondent à la bonne source de l'horloge.
Types¶
De nouveau type d'entier sont fournis avec la librairie <stdint.h>
.
L'utilisation de ces types DOIT être utilisé afin d'exprimer le nombre de bit d'un objet.
Progmem¶
Pour mettre des variables en lecture seule dans la section FLASH au lieu de SRAM avec <avr/pgmspace.h>
.
L’accès à ces variables est faite via les macros de la librairie.
Le nom de la variable DOIT être suivie de _P
Exemple :
#include <avr/pgmspace.h>
...
/** @brief Variable en FLASH */
const int Variable1_P PROGMEM = 42;
Fonction main¶
Un microcontrôleur AVR ne termine jamais la fonction main
.
- Déclarer la fonction main avec l’attribut
noreturn
- La boucle sans fin la plus optimisé est le
for (;;)
Justification : AVR035
Exemple :
/**
* @brief Never ending loop
*/
void main(void) __attribute__ ((noreturn));
/* main function definition */
void main(void) {
...
/* never return */
for (;;) {
};
};
Atomic¶
Opérations ne devant pas être interrompus comme charger un registre de 16 bits avec un registre de 8 bits.
La librairie avr-libc
(util/atomic.h) fournit des macros permettant la gestion entre autre des interruptions.
Les instructions critiques sont insérées dans un ATOMIC_BLOCK
.
Exemple :
...
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
...
}
...
Mis à jour par Patrice Nadeau il y a plus d'un an · 17 révisions