Wiki » Historique » Révision 42
« Précédent |
Révision 42/170
(diff)
| Suivant »
Patrice Nadeau, 2023-08-16 20:06
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¶
- Les fonctions, variables, constantes et
#define
DOIVENT être en anglais américain - Les commentaires et documentation DOIVENT être en français
Justifications :
- Support ASCII 7-bits
- Correspondance avec la fiche technique (datasheet)
- Loi sur la langue officielle et commune du Québec, le 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`
* @remark Note non importante
* @note Note générale
* @attention Note importante
* @warning Note conséquence négative
* ```
* code
* ```
*/
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 librairie
* @author Patrice Nadeau <pnadeau@patricenadeau.com>
* @version 0.0.02
* @date 2023-03-27
* @pre AVR supportes (testés en gras):
* - 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¶
En général : librairie_action_sujet
- Comporter au maximum 31 caractères
- Être séparées par des traits de soulignement si comporte plusieurs mots
- Exceptions :
- Fonction et variables DOIVENT
- Être en minuscule
- Macros, constantes et
#define
DOIVENT- Être en majuscule
- Fonction et variables DOIVENT
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
ouextern
selon le besoin
Exemple :
/**
* @name Liste des constantes
* @brief
*/
/** @{ */
/** @brief La chaîne d'initialisation du projet */
static const char INIT_STR[6] = "POWER";
/** @brief Constante globale de la librairie `random` */
extern int RANDOM_MAX = 25;
/** @} */
/** @brief Constante */
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 de la structure dans la librairie `ds1305` */
typedef struct {
/** @brief Dernier deux chiffres : ≥ 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 Variable locale */
static int ctr;
/** @brief Variable globale */
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, get, clear : Règle, obtient ou vide un registre
- read, write : Lis ou écris dans un fichier
- init : Fonction d’initialisation
- is : Vérifie un état
- setup : Fonction de configuration des ports (AVR)
Exceptions
- 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.
Une fonction DEVRAIT retourner une valeur.
- Type entier (oui/non) :
- Succès : 0
- Erreur : 1
- Type booléen (Librairie
<stdbool.h>
)- true
- false
- Pointeur :
- NULL : Erreur
- Autre valeur : adresse du pointeur
Justification :
Exemple :
/**
* @brief Vérifie si une horloge est est initialisée
* @param[in] nb Timer number. @n Possible values :
* − @arg **TIMER_1**
* − @arg **TIMER_2**
* @return
* @retval true Horloge *nb* est initialisée
* @retval false Horloge *nb* n'est PAS initialisée
* @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¶
Vérification du modèle de microcontrôleur
> Via l'option -m
de gcc
#ifndef defined (__AVR_ATmega48__) || (__AVR_ATmega48P__) || \
(__AVR_ATmega88P__) || defined (__AVR_ATmega88__) || \
(__AVR_ATmega168__) || defined (__AVR_ATmega168P__) || \
(__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
#warning "Cette librairie n'as pas été testée sur cette famille de microcontrôleur."
#endif
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 :
#include <avr/io.h>
/**
* @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 · 42 révisions