5.1. Coding Rules French

5.1.1. Règles et bonnes pratiques de codage

Glossaire

TermeDfinition
CC programming language langage de programmation C
CPUCentral Processing Unit processeur
DRVDriver pilote logiciel
EGOSerRTOSgener Operating System systme dexploitation eRTOSgener
HALHardware Abstraction Layer couche dabstraction matrielle
IoTInternet Of Things Internet des objets
MCUMicro Controller Unit microcontrleur
OS Operating System systme dexploitation

5.1.1.1. But du document

Ce document prsente les normes de codages en C mises en place ERTOSGENER pour le projet de dveloppement de lOS propritaire EGOS.

Il est demand aux contributeurs d'EGOS de bien vouloir respecter ces rgles afin de conserver une uniformit dans l'ensemble de l'OS.

Ces rgles peuvent parfois drouter par rapport aux strandards actuels mais elles ont t talies dans l'unique but d'amliorer la lisibilit et donc la maintenance du code. En effet, du fait du dveloppement dun OS et donc de la complexit inhrente celui-ci, un rafrachissement des rgles simposait.

5.1.1.2. Règles de nommage

Donner un nom pertinent un fichier, un module ou une variable doit fournir au lecteur suffisamment dinformations sur le contexte ou le type de donne sans avoir recours systmatiquement la documentation ou laide contextuelle de lditeur de code.

5.1.1.2.1. Notation Hongroise

La notation dite Hongroise consiste donner un prfixe spcifique un nom. Il existe deux variantes en informatique, la base dite systme et la base dite applicative.

5.1.1.2.1.1. Base système

La notation systme prfixe le nom dune variable avec une indication de son type de donne. Dans le dveloppement embarqu, o le type des donnes est important, cette information peut tre utile.

    uint16_t u16MyVar;

Nanmoins le plus grand point noir de cette notation est lorsque lon change le type de donne dune variable, il faut alors imprativement reflter ce changement dans le nom de toutes les variables concernes travers tous les projets impacts, multipliant de fait les sources derreur et de check-out.

    uint32_t u16MyVar;              // inconsistance en cas de changement de type

Un type de prfixe plus basique indiquant le genre de la variable (numrique, tableau, pointeur) sans donner le type prcis peut tre une alternative viable et fonctionnelle.

    uint32_t nMyVar;                // numrique, mais  charge de la dclaration de fixer le type
  • Utiliser la base systme avec logique pour dfinir des types gnriques (n) plutt que spcifique (u16)
5.1.1.2.1.2. Base applicative

Les prfixes de base applicative indiquent de faon gnrale le contexte de lusage dune variable, par exemple Pos pour Position, Alt pour Altitude, etc. Cette approche est elle aussi retenue par lusage dune combinaison logique.

    uint32_t nAltCurr, nAltPrev;            // Altitude courante et prcdente
  • Utiliser la base applicative pour dcrire le contexte dutilisation dune variable, membre, paramtre (Alt)
  • Ne pas utiliser de nom de variable ou fonction dune seule lettre (i, j, k, l, x, y, z) ou trop vague (open, add)

5.1.1.2.2. Arborescence des répertoires

Les rpertoires sont utiliss afin de structurer physiquement les abstractions virtuelles telles que la sparation de code, les couches logicielles et les composants. Ces couches sont dcrites dans le document darchitecture dont ce document ne se substitue pas, les rgles de codage tant vocation gnraliste bien quapplique sur EGOS en particulier.

Pour exemple, EGOS est dcoup en couches logicielles de la faon suivante:

EGOS_Architecture

En consquence, cette organisation se retrouve dans larborescence des rpertoires, ce qui permet de sy retrouver rapidement et deffectuer les dpendances logiques entre les couches par lautorisation ou la restriction dinclusions.

Voici la structure des fichiers de l'OS disponible pour les contributeurs:

EGOS_File_Structure
  • Les couches infrieures ne peuvent accder aux couches suprieures
  • Les couches suprieures ne peuvent accder qu la ou les couches directement infrieures
  • Les couches suprieures ne peuvent accder la couche infrieure qu travers une interface
  • Les couches peuvent toutes accder aux couches transverses de service (OSS, FUN, UTL, )

5.1.1.2.3. Fichier

Donner un nom un fichier est aussi important que donner un nom un livre : il doit clairement dcrire son contenu. Une convention de nommage des fichiers assure une mthode robuste et cohrente pour trier les fichiers en fonction de leur couche logicielle, leur fonctionnalit ainsi que leur usage.

Convention de nommage d'un fichier
SectionDescription
CoucheLa couche logicielle courante doit tre indique dans le nom de fichier
ModuleEn gnral on applique la rgle dun Module par fichier. De fait le nom do module doit se reflter dans le nom du fichier
FonctionLe groupe de fonctionnalit ou spcifique doit suivre hirarchiquement la couche et le module

La construction typique dun nom de fichier est la suivante :

    "couche"_"module"_"fonction".c/cxx/h                                    // utl_str_format.c

Dans labsolu tous les fichiers pourraient tre copis dans un rpertoire unique sans gnrer de conflit mais permettre nanmoins de retrouver larborescence originale avec un simple classement par ordre alphabtique.

Un fichier peut tre une extension dun fichier parent afin disoler une partie des dfinitions ou de code afin dallger la maintenance du fichier parent. Un fichier peut aussi tre une implmentation spcifique dune interface de programmation adapte une architecture ou une technologie particulire.

    "couche"_"module"_"fonction"__cfg.h                                             // mcu_cpu_core__cfg.h
    "couche"_"module"_"fonction"__impl_"arch".c/cxx/h               // mcu_cpu_core__impl_armv7m_.c
    "couche"_"module"_"fonction"__impl_"arch"__cfg. h               // mcu_cpu_core__impl_armv7m__cfg.h
  • Le nom du fichier reflte la couche laquelle il appartient
  • Le nom du fichier reflte le module quil contient
  • Le nom du fichier reflte la fonctionnalit quil implmente
  • Le nom de fichier est crit en snake_case
  • Le nom de fichier est crit en anglais, avec deux _ en sparation dune fonctionnalit ou architecture
  • Le nom du fichier c et du fichier h sont les mmes et respectent la mme typographie
  • Le nom du fichier c de niveau se termine par un _ pour filtrage de compilation
  • Les fichiers cxx de sous-inclusion ne sont pas inclure directement dans le process de compilation
  • Les fichiers h doivent disposer dun mcanisme de protection des inclusions multiples (pragma ou ifdef)

5.1.1.2.4. Variable

Le nom dune variable est compos de diffrentes parties dcrivant son contexte, son type et sa porte.

  • Le nom de la variable est crit en anglais, sans ngation pour viter les problmes de logique
  • Le nom de la variable utilise la premire lettre de chaque mot en majuscule sans sparation (PascalCase)
  • Le nom de la variable est prfix en fonction de sa porte et de son type
  • Une seule variable par ligne, pas de mlange avec les pointeurs qui sont crit sur des lignes propres
  • Les variables sont crire en dbut de fonction/mthode pour viter des rservations de pile ultrieures
  • Les variables sont crire en dbut de fonction/mthode pour viter les conflits de sous contexte
  • Les variables doivent tre initialises lors de leur dclaration afin de gagner en lisibilit et en taille de code
5.1.1.2.4.1. Contexte

Afin de saisir le contexte dusage dune variable, il est donc conseill dindiquer une information de type base systme gnrique afin de distinguer les nombres des pointeurs, les tableaux des structures. Pour cela une liste non exhaustive de prfixe est dfinie.

Type Prfixe Exemple Explication
Prfixes en fonction de la porte dune variable
Array a aArray Array
Boolean b bBool Boolean, TRUE/FALSE
Constant c cConstant Constant value, understand read-only
Define d dDefine Simple define, defined value or defined type
Enum e eEnum Enum list element
Function f fFunction Typically a function pointer
Handle h hHandle Handle, identifier, implementation dependent (often a pointer)
Iterator i iIterator Like STL iterator
Macro m mMacro Preprocessor macro, mostly compiler dependent, beware
Number n nNumber Char, long, int, float, double, complex, rational, ...
Object o oObject C++ class, complex structure with embedded functions, ...
Pointer p, pp pPointer Typically a 32 bits address, the double pointer is noted pp
Reference r rReference Reference (C++), always bound and never NULL, unlike pointer
Struct s sStruct Structure
Template t tTemplate Template (C++ only) but can be emulated using macro
Union u uUnion Union, join two or more values of the same size under a common name
Volatile v vVolatile Volatile data, understand not-cached, but can also be constant (read-only)
  • Utiliser une combinaison de prfixe pour affiner la signification du contexte (an Array of Number)
  • Certains types redfinis utilisent cette convention de nommage et vitent davoir dclarer const ou volatile
5.1.1.2.4.2. Type de donnée

Les types de donnes du langage C sont un peu compliqus lire et/ou crire. Aussi une version plus compacte a t redfinie.

Prfixes en fonction du type de donne des variables
Type de donne C originalType redfiniDECL(x) / __CAST(x)Prfixe
Signed Signed Signed Signed
BoolenboolboolbB1bB1bb
Entiercharunsigned charnS8nU8S8 / __S8U8 / __U8nn
shortunsigned shortnS16nU16S16 / __S16U16 / __U16nn
longunsigned longnS32nU32S32 / __S32U32 / __U32nn
long longunsigned long longnS64nU64S64 / __S64U64 / __U64nn
Int <=arch>unsigned int <=arch>nSnUS / __SU / __Unn
hexadecimalH /
FlottantfloatfloatnF32nF32F32 / __F32F32 / __F32nn
doubledoublenF64nF64F64 / __F64F64 / __F64nn
long doublelong doublenF96nF96F96 / __F96F96 / __F96nn
<=arch><=arch>nFnFF / __FF / __Fnn
Constantconst Intconst unsigned intcnScnUcncn
Volatilevolatile intvolatile unsigned intvnSvnUvnvn
PointeurInt*unsigned int*pnSpnUpnpn
Tableauint []unsigned int []nSnUanan
VoidvoidvoidVoidVoidpp
Sizesize_tssize_t (gcc)SizeSizenn
Timetime_ttime_tTimeTimenn
Stringchar*unsigned char*nStr_OsnStr_OsSTR_OS /STR_OS /anan
  • Dfinir les paramtres en entre en const (prfixe c) autant que possible
  • Si un accs en lecture par pointeur un paramtre, le protger par un const
  • Drfrencer un pointeur (hors tableau) en utilisant *
  • Dans le cas d'un pointer sur un tableau, ne pas utiliser * mais utiliser le prfixe p et laccs lindex [0]
  • Utilisez en priorit des nombres signs plutt que des nombres non signs, sauf si rellement ncessaire
  • Utilisez en priorit les redfinitions adaptes larchitecture cible (nS, nU ou nF en 32 bits sur STM32L4)
  • Initialiser les pointeurs de fonction vers un callback par dfaut (stub) mais jamais NULL
  • Initialiser les pointeurs de donnes NULL et vrifier quils ne sont pas NULL avant de les utiliser
  • Utiliser des fonctions de type "accesseur" plutt quun accs direct aux variables statiques depuis lextrieur
  • Faire attention la prcdence des modificateurs volatile et constant (pcnConstData vs. cpnConstPointer)
5.1.1.2.4.3. Portée

La porte dusage dune variable / constante ou membre indique son contexte et son accessibilit travers la hirarchie du code source.

Prfixes en fonction de la porte dune variable
Prfixe/Variable/Membre Porte Contexte
g_xxx Globale externe Lecture / criture
g__xxx Globale statique au fichier, ne pas dclarer en extern Lecture / criture
l_xxx Locale la fonction/mthode, dclar au dbut Lecture / criture
i_xxx Paramtre en entre Lecture (constant de prfrence)
o_xxx Paramtre en sortie Lecture / criture
io_xxx Paramtre en entre et sortie Lecture / criture
m_xxx Membre publique (struct ou C++) Lecture / criture (hrit en C++)
mp_xxx Membre protg (struct ou C++) Lecture / criture (hrit en C++)
mpp_xxx Membre priv (struct ou C++) Lecture / criture (hrit en C++)

Une convention de nommage claire entre les variables locales et membres doit tre faite afin de pouvoir les distinguer aisment sans avoir recours un environnement de dveloppement avanc. Par exemple, la place de ceci:

    nCharOut = nCharIn;                             // transmission dun caractre, mais porte gnrale floue

Ecrire ceci a plus de sens et indique le contexte de chaque variable / constante / membre:

    l_nCharOut = m_nCharIn;                 // transmission dun caractre, mais porte plus claire
  • Ne pas dfinir de variable globale, mais il est possible de dfinir des constantes (valeur, tableau) globales
  • En cas dattribut statique, la porte de la variable / constante / membre est suivie de deux _ en sparation
5.1.1.2.4.4. Combinaison

Une combinaison des diffrents prfixes peut tre ralise en suivant la rgle suivante :

    <portee>_<contexte>NomDeVariable

Voici quelques exemples :

Exemples de nommage de variable ou constante
Type de donne Nom de variable
cnS16 g_acnGlobalVariable[]
pnU8 io_panParameter
vcnU32 l_vcnLocalVariable
pcnU32 l_apcnAttributes[]
sBusIdentifier m_asBusIdList[]
poCosem l_poCosemInput

Une bonne pratique de lecture de la combinaison est de lire en anglais littral de gauche droite :

    l_pvcnLocalVariable                     // local pointer on volatile read-only number (ie. maybe a R-O register)
    g__asMapper                                     // global non-extern (static) array of structures
    mp_uTcpFrame                            // protected union member (not a macro because not CAPITAL_CASE)
  • Le nom de la variable (acn) doit reflter le contexte de son type (cn) afin daider la comprhension du code
  • Si la modification dattribut d'une variable a un impact majeur (c, v) alors il faut modifier le nom de cette variable en consquence
  • Le pointeur p (pPointer) peut tre assez facilement assimil un pointeur sur tableau pa dans un nom
  • Faire attention lordre des attributs de contexte p et a (apArrayOfPointer vs. paPointerOnArrayOf)

5.1.1.2.5. Type des données

Plusieurs types de donnes du langage C ont t redfinis grce des instructions prprocesseur.

5.1.1.2.5.1. Définition simple

Une dfinition vide est la simple dclaration dune tiquette sans paramtre complmentaire. Cela permet notamment de permettre la compilation conditionnelle de certaines parties de code lintrieur dun fichier sans avoir dupliquer ceux-ci et spcialiser plus particulirement des implmentations redondantes.

    /// \def        pour documenter un #define vide
    #define dDEF_TST__USE_IT
  • Le nom dun define commence par un d minuscule (dDefine)
  • Le nom dun define est crit en CONSTANT_CASE avec un _ en sparation des mots
  • Le nom dun define commence par la couche et le module voire la fonction
  • Le nom dun define est crit en anglais, avec deux _ en sparation de lidentifiant unique (USE_IT)
  • Ne pas mettre de commentaire C++ (//) sur la mme ligne quun define (risque dtre mal interprt)
  • Ne mettre le define dans un fichier h que sil a une porte extrieure un module, sinon le mettre au dbut du fichier c
5.1.1.2.5.2. Constantes

Une dfinition suivie dun paramtre numrique constant (nombre, chane de caractres) permet de remplacer la rfrence la dfinition par son contenu.

    /// \def        pour documenter une constante
    #define cDEF_TST__VALUE (1024)
  • Le nom dune constante commence par un c minuscule (cConstant)
  • Le nom dune constante est crit en CONSTANT_CASE avec un _ en sparation des mots
  • Le nom dune constante commence par la couche et le module voire la fonction
  • Le nom dune constante est crit en anglais, avec deux _ en sparation de lidentifiant unique (VALUE)
  • Ne pas mettre de commentaire C++ (//) sur la mme ligne dune constante (risque dtre mal interprt)
  • Si besoin, entourer la valeur de parenthses pour viter les agrgations pouvant tre mal interprtes (##)
  • Ne mettre la constante dans un fichier h que sil a une porte extrieure un module, sinon au dbut du c
5.1.1.2.5.3. Macro

Les macros se comportent comme des constantes dans le sens quelles induisent une substitution syntaxique par le prprocesseur, mais permettent en plus dinclure des paramtres extrieurs qui seront injects dans le code substitu. Aucune valuation du code, de vrification de type ou de cohrence na lieu cette tape. Il est donc possible dimbriquer lappel des macros, en prenant soin nanmoins de produire un code final syntaxiquement correct pour ltape de compilation.

    /// \def        pour documenter une macro
    #define mDEF_TST__MACRO(val)                            \
                    (val * cDEF_TST__VALUE)
  • Le nom dune macro commence par un m minuscule (mMacro)
  • Le nom dune macro est crit en CONSTANT_CASE avec un _ en sparation des mots
  • Le nom dune macro commence par la couche et le module voire la fonction
  • Le nom dune macro est crit en anglais, avec deux _ en sparation de lidentifiant unique (MACRO)
  • Ne pas mettre de commentaire C++ (//) sur la mme ligne dune macro (risque dtre mal interprt)
  • Entourer lexpression de parenthses pour viter les effets de bord de prcdence / priorit
  • Utiliser le caractre \ en fin de ligne pour pouvoir poursuivre la dfinition de la macro sur la ligne suivante
  • Ne mettre la macro dans un fichier h que sil a une porte extrieure un module, sinon au dbut du c
5.1.1.2.5.4. Numérique

La dfinition de nouveaux types numriques drivs des types originaux ou dj redfinis par EGOS est possible. Une macro simplifie la dclaration de toutes les variantes possibles.

    DECL_NUMERIC(int, nS32_Plus);
  • Le nom dun type numrique commence par un n minuscule (nNumber)
  • Le nom dun type numrique indique minima la signature dun nombre ngatif S et la taille du type
  • Le nom dun type numrique est crit en PascalCase avec un _ en sparation dune extension
  • Utiliser la macro DECL_NUMERIC pour dfinir un nouveau type numrique
  • La variation du type numrique est automatiquement effectue avec la macro DECL_ NUMERIC
5.1.1.2.5.5. Fonction

Les pointeurs de fonctions sont utiles dans le cas dappels de retour, communment appeles callback. Une macro simplifie la dclaration de toutes les variantes possibles.

    DECL_FUNCTION(void, fDefTsts_Cb, (pnS32 i_panData));
  • Le nom dune fonction commence par un f minuscule (fFunction)
  • Le nom dune fonction commence par la couche et le module voire la fonctionnalit implmente
  • Le nom dune fonction est crit en PascalCase avec un _ en sparation de la fonctionnalit
  • Utiliser la macro DECL_FUNCTION avec les paramtres entre parenthses pour dfinir une fonction
5.1.1.2.5.6. Enum

Les constantes de type dnumration permettent de dfinir une suite incrmentale de constantes. En soit, les membres dun numrateur doivent tre cris en majuscule. La premire entre doit tre initialise la valeur requise, mme si elle est zro.

    /// \enum       pour documenter un numrateur
    DECL_TYPEDEF(enum, eDefTst_Enum)
    { eDEF_TST__ENUM__START = 0                                                     ///< Explication
    , eDEF_TST__ENUM__MIDDLE                                                        ///< Explication
    , eDEF_TST__ENUM__END                                                           ///< Explication
    //
    , eDEF_TST__ENUM                                                                        ///< Nombre dnumrateur maximum (ici = 3)
    // Aliases
    , eDEF_TST__ENUM__TEST = eDEF_TST__ENUM__START          ///< Explication alias
    }       DECL_INSTANCE(eDefTst_Enum);                                    // Gnre eDefTst_Enum, peDefTst_Enum, ...

    eDefTst_Enum            l_eEnum;

Pour des questions de lisibilit et de suivi de lecture, il est prfrable de mettre les virgules , en dbut de ligne et alignes sur laxe des accolades afin davoir un fil conducteur qui symbolise lensemble des entres comme faisant visuellement partie du mme groupe dnumration.

Il est aussi facile de compter les entres dnumrateur en reprant les virgules , toutes alignes verticalement.

  • Le nom dun numrateur commence par un e minuscule (eEnum)
  • Le nom dun numrateur commence par la couche et le module voire la fonction
  • Le nom dun numrateur est crit en PascalCase avec un _ en sparation dun domaine
  • Utiliser les macros DECL_TYPEDEF et DECL_INSTANCE avec le mme nom pour dfinir un numrateur
  • La variation du type de lnumrateur est automatiquement effectue avec la macro DECL_INSTANCE
  • Il est possible de dcliner le mme numrateur (alias) en multipliant lusage de la macro DECL_INSTANCE
  • Une entre dnumrateur commence par un e minuscule (eEnum)
  • Une entre dnumrateur est crite en CONSTANT_CASE avec deux _ en sparation dun domaine
  • Une entre dnumrateur commence par la couche et le module voire la fonction, le domaine puis la valeur
  • La premire entre dun numrateur doit tre initialis sa valeur requise, mme si par dfaut 0
  • Un numrateur se termine toujours par une entre avec domaine vide pour connaitre le nombre dentres
  • Ne mettre lnumrateur dans un fichier h que sil a une porte extrieure un module, sinon au dbut du c
  • Une entre dnumrateur ne se termine pas par une virgule , car elle est au dbut de la ligne suivante
  • Une accolade fermante } doit se trouver sur la mme colonne que laccolade ouvrante { associe
  • Les virgules , de sparation des entres de lnumrateur doivent tre alignes avec les accolades
5.1.1.2.5.7. Structure

Les membres dune structure respectent lusage des prfixes dfinit prcdemment. Afin de forcer une occupation mmoire idale des structures, il faut aider le compilateur en dfinissant les donnes membres de taille plus importante en premier, suivi des membres de taille dcroissante.

    /// \struct pour documenter une structure C
    DECL_TYPEDEF(struct, sDefTst_Struct)
    { nU32                          nSize                           ///< Explication
    ; eDefTst_Enum          eType                           ///< Explication
    ; pfDefTsts_Cb          pfCb                            ///< Explication
    ;}      DECL_INSTANCE(sDefTst_Struct);          // Gnre sDefTst_Struct, psDefTst_Struct, ...

    sDefTst_Struct          g_asStruct[3];

    g_asStruct[0].nSize;
    g_asStruct[0].eType;
    g_asStruct[0].pfCb;

Pour des questions de lisibilit et de suivi de lecture, il est prfrable de mettre les points-virgules ; en dbut de ligne et alignes sur laxe des accolades afin davoir un fil conducteur qui symbolise lensemble des membres comme faisant visuellement partie de la mme structure. Il est aussi facile de compter les membres dune structure en reprant les points-virgules ; tous aligns verticalement.

  • Une structure organise des donnes dans lordre de dclaration
  • Un ventuel alignement mmoire peut avoir lieu entre les membres dune structure suivant leurs tailles
  • Placer les types de taille plus grands en premier puis par ordre dcroissant
  • Le regroupement des types par taille est privilgier par rapport au regroupement par thme
  • Le nom dune structure commence par un s minuscule (sStruct)
  • Le nom dune structure commence par la couche et le module voire la fonction
  • Le nom dune structure est crit en PascalCase avec un _ en sparation dun domaine
  • Utiliser les macros DECL_TYPEDEF et DECL_INSTANCE avec le mme nom pour dfinir une structure
  • La variation du type de la structure est automatiquement effectue avec la macro DECL_INSTANCE
  • Il est possible de dcliner la mme structure (alias) en multipliant lusage de la macro DECL_INSTANCE
  • Le nom dun membre de la structure commence par une lettre minuscule correspondant son type gnrique
  • Le nom dun membre de la structure est crit en PascalCase
  • Le nom dun membre de la structure doit rester plus clair et court que le nom dune variable car contextualis
  • Eventuellement crer une sous-structure nomme ou anonyme pour regrouper des membres communs
  • Un membre de structure ne se termine pas par un point-virgule ; car il est au dbut de la ligne suivante
  • Une accolade fermante } doit se trouver sur la mme colonne que laccolade ouvrante { associe
  • Les points-virgules ; de sparation des membres de la structure doivent tre aligns avec les accolades
5.1.1.2.5.8. Champs de bits

Les champs de bits sont des structures spciales o les membres sont dfinis sur un certain nombre de bits. Le numro de bit dmarre zro, le nombre de bits est cumulatif et ne doit pas dpasser la taille du type de donne slectionn. Le nom du membre ne doit ni spcifier sa position physique ni sa taille en bit.

    /// \struct pour documenter une structure C
    DECL_TYPEDEF(struct, sDefTst_Bf)
    { nU32                  nSize:16                        ///< Explication
    ; nU32                  _16:4                           ///< Explication
    ; nU32                  nType:8                         ///< Explication
    ; nU32                  _28:4                           ///< Explication
    ;}      DECL_INSTANCE(sDefTst_Bf);              // Gnre sDefTst_Bf, psDefTst_Bf ,

    sDefTst_Bf      g_sBitfield;

    g_sBitfield.nSize;
    g_sBitfield nType;

Ne jamais accder un champ de bit avec un dcalage et un masque binaire, laisser le compilateur sen occuper, sinon en cas dvolution/modification du champ de bit, il faut aussi modifier le code en consquence. Il y a peu de chance que cela soit effectu.

Pour des questions de lisibilit et de suivi de lecture, il est prfrable de mettre les points-virgules ; en dbut de ligne et alignes sur laxe des accolades afin davoir un fil conducteur qui symbolise lensemble des membres comme faisant visuellement partie du mme champ de bits. Il est aussi facile de compter les membres dun champ de bits en reprant les points-virgules ; tous aligns verticalement.

  • Le membre du champ de bits appartient forcment une structure
  • Les membres dun champ de bits partagent tous un type de donne commun jusqu dpasser sa capacit
  • En cas de changement de type, un alignement de donne consommateur en place survient, viter donc
  • Placer les types de taille plus grands en premier puis par ordre dcroissant, sauf si lordre est spcifique
  • Utiliser ventuellement la directive prprocesseur #pragma pack pour modifier la taille de lalignement
  • Le nom dun membre du champ de bits commence par une lettre minuscule correspondant son type
  • Le nom dun membre du champ de bits est crit en PascalCase
  • Le nom dun membre du champ de bits doit rester plus clair et court que le nom dune variable
  • Le nom dun membre du champ de bits nindique ni le bit de dpart, de fin ou sa taille
  • Le nombre de bits des membres dun mme type de donne ne doit pas dpasser sa taille
  • Effectuer du remplissage de bits vides au besoin pour passer sur un nouveau / autre type de donne
  • Le nom dun membre vide du champ de bits commence par un _ et indique le bit de dpart
  • Ne jamais effectuer un accs un membre du champ de bits par des dcalages et masques de bits
  • Mais alors jamais, parce que si le champ de bits volue, en gnral pas les accs par dcalages/masques
  • Un membre de champ de bits ne se termine pas par un point-virgule ; car il est au dbut de la ligne suivante
  • Une accolade fermante } doit se trouver sur la mme colonne que laccolade ouvrante { associe
  • Les points-virgules ; de sparation des membres du champ de bits doivent tre aligns avec les accolades
5.1.1.2.5.9. Union

Une union est un accesseur dune mme adresse mmoire en utilisant une autre structure de donne. Leurs tailles ne doivent pas ncessairement correspondre, la taille de lunion correspondra la taille du membre de taille maximum en prenant en compte les effets du padding et de lusage de loprateur pragma pack.

    /// \union      pour documenter une union
    DECL_TYPEDEF(union, uDefTst_Union)
    { struct
            { nU32                  nSize:16                ///< Explication
            ; nU32                  nType:8                 ///< Explication
            ;}              sFile                                   ///< Explication
    ; nU64          nFlat                                   ///< Explication
    ;}      DECL_INSTANCE(uDefTst_Union);   // Gnre uDefTst_Union, puDefTst_Union, ...

    uDefTst_Union   l_uUnion;

    l_uUnion.sFile.nSize;
    l_uUnion sFile.nType;
    l_uUnion nFlat;                                         // == l_uUnion sFile
    // sizeof(uDefTst_Union) == sizeof(nU64)

Pour des questions de lisibilit et de suivi de lecture, il est prfrable de mettre les points-virgules ; en dbut de ligne et alignes sur laxe des accolades afin davoir un fil conducteur qui symbolise lensemble des membres comme faisant visuellement partie de la mme union. Il est aussi facile de compter les membres dune union en reprant les points-virgules ; tous aligns verticalement.

  • Une union peut servir reprsenter une mme zone mmoire utilise des moments distincts
  • Placer les types de taille plus grands en premier puis par ordre dcroissant, sauf si lordre est spcifique
  • Utiliser ventuellement la directive prprocesseur #pragma pack pour modifier la taille de lalignement
  • Une union de structures est souvent utilise au sein d'EGOS pour dcrire les variations dun message
  • Le nom dune union commence par un u minuscule (uUnion)
  • Le nom dune union commence par la couche et le module voire la fonction
  • Le nom dune union est crit en PascalCase avec un _ en sparation dun domaine
  • Utiliser les macros DECL_TYPEDEF et DECL_INSTANCE avec le mme nom pour dfinir une union
  • La variation du type de lunion est automatiquement effectue avec la macro DECL_INSTANCE
  • Il est possible de dcliner la mme union (alias) en multipliant lusage de la macro DECL_INSTANCE
  • Le nom dun membre de lunion commence par une lettre minuscule correspondant son type gnrique
  • Le nom dun membre de lunion est crit en PascalCase
  • Le nom dun membre de lunion doit rester plus clair et court que le nom dune variable car contextualis
  • Placer les membres de lunion pouvant tre accd en commun au mme niveau dindentation
  • Un membre dune union ne se termine pas par un point-virgule ; car il est au dbut de la ligne suivante
  • Une accolade fermante } doit se trouver sur la mme ligne/colonne que laccolade ouvrante { associe
  • Les points-virgules ; de sparation des membres dune union doivent tre aligns avec les accolades
5.1.1.2.5.10. Tableau

Les tableaux de constantes sont dclarer en mettant les virgules de sparation en dbut de ligne plutt qu la fin.

    csDefTst_Struct g_acsStruct             // Tableau de constantes
                                    [3]
    //              .nSize    .eType                                .pfCb                           eIndex
    =       { { .nSize = 1, .eType = eDEF_TST__ENUM__START,         .pfCb = (def_tst_Cb) }          // 0
            , { .nSize = 2, .eType = eDEF_TST__ENUM__MIDDLE,        .pfCb = (def_tst_Test) }        // 1
            , { .nSize = 4, .eType = eDEF_TST__ENUM__END,           .pfCb = NULL }                          // 2
            };

    __STATIC
    sDefTst_Struct          g__sStruct
    =       { { 0 }                 // Initialise  0 toute la structure, quivalent memset(0) ou bzero()
            , .eType = eDEF_TST__ENUM__MIDDLE
            , .nSize = 4    // Les membres nomms peuvent tre initialiss dans le dsordre
            };

Pour des questions de lisibilit et de suivi de lecture, il est prfrable de mettre les virgules , en dbut de ligne et alignes sur laxe des accolades afin davoir un fil conducteur qui symbolise lensemble des lignes comme faisant visuellement partie du mme tableau. Il est aussi facile de compter les lignes du tableau en reprant les virgules , toutes alignes verticalement.

  • Passer la ligne pour chaque ligne de tableau
  • Toujours affecter nommment les lments dune structure, au cas o le contenu de la structure volue
  • Toujours dclarer/spcifier la taille du tableau afin de permettre au compilateur de vrifier la cohrence
  • Mettre la taille du tableau ([3]) sur une ligne en-dessous pour bien isoler visuellement la dimension
  • En cas de tableau multi-dimensionnel, mettre chaque indice sur une ligne diffrente, aligns verticalement
  • Utiliser une ligne de commentaire avant les lignes du tableau afin dexpliquer chaque colonne
  • Une ligne de tableau ne se termine pas par une virgule , car elle est au dbut de la ligne suivante
  • Une accolade fermante } doit se trouver sur la mme colonne que laccolade ouvrante { associe
  • Les virgules , de sparation des lignes du tableau doivent tre alignes avec les accolades

5.1.1.3. Règles de style

Le formatage du code source est important pour reprer visuellement sa structure et la hirarchie des instructions.

5.1.1.3.1. Sections

Un code source c typique est dcoup en plusieurs sections. Il est ncessaire de les identifier clairement pour une lecture aise. Il nest pas toujours possible de respecter la topologie exacte des sections, lordre des dclarations pouvant tre lgrement diffrente de la recommandation, et appelle donc une certaine flexibilit, surtout dans les fichiers dimplmentation c.

5.1.1.3.1.1. Include

Aprs lentte du fichier il y a en gnral la section des fichiers include.

    // - - - HEADER INCLUSION  - - - - - - - - - - - - - - - - - - - - - - - - - - -

    #include "egos.h"                               // Fichier dinclusion des dfinitions publiques

    // - - - HIERARCHIC INCLUSION  - - - - - - - - - - - - - - - - - - - - - - - - -

    #include "utl_str.h"                    // quand dans la mme couche, inclure simplement le fichier
    #include "./mcu_cpu.h"                  // quand dans une autre couche, ajouter ./ pour lindiquer
  • Prfrer les chemins relatifs dans les oprateurs dinclusion, voire les ajouter aux options de compilation
  • Linclusion des fichiers standards se fait au format voir et non pas "fichier.h"
  • EGOS ne faisant pas appel aux fichiers standards, en gnral cela ne devrait pas sappliquer
  • Les inclusions cherchent dabord dans les chemins du compilateur, puis les chemins utilisateur
  • Les inclusions "fichier.h" cherchent dabord dans les chemins utilisateur, puis les chemins du compilateur
  • Attention lordre des chemins dinclusion, surtout si un fichier inclure se retrouve plusieurs endroits
  • Ne pas utiliser la directive prprocesseur #include_next qui est rserver aux fichiers du compilateur
5.1.1.3.1.2. Define – typedef – macro

Avant le code source (dans les fichiers c) ou la dclaration des fonctions (dans les fichiers h) il y a une section de dfinition de macro et/ou constantes.

    // - - - CONSTANT DEFINITION - - - - - - - - - - - - - - - - - - - - - - - - - -

    #define cDEF_TST__VALUE (1024)

    // - - - DATATYPE DEFINITION - - - - - - - - - - - - - - - - - - - - - - - - - -

    DECL_TYPEDEF(struct, sDefTst_Bf)
    { nU32                  nSize:16                                ///< Explication
    ; nU32                  nType:8                                 ///< Explication
    ;}      DECL_INSTANCE(sDefTst_Bf);                      // Gnre sDefTst_Bf, psDefTst_Bf, ...

    // - - - MACRO DEFINITION  - - - - - - - - - - - - - - - - - - - - - - - - - - -

    #define mDEF_TST__MACRO(val)                    \
                             (val * cDEF_TST__VALUE)
  • La section CONSTANT inclue les define vides (dDefine) et les valeurs constantes (cConstant)
  • La section DATATYPE inclue toutes les macro DECL_xxx (numrique, fonction, enum, struct, union) dans lordre le plus adapt pour rinclure des dfinitions prcdentes dans celles qui suivent
  • La section MACRO inclue toutes les macros de substitution de code
5.1.1.3.1.3. Déclaration globale et externe

Certaines variables peuvent avoir une porte globale au fichier (attribut static) ou au projet (attribut extern).

    // - - - GLOBAL DECLARATION      - - - - - - - - - - - - - - - - - - - - - - - - - -

    static sDefTst_Struct           g__sStruct;                     ///< Porte interne au fichier

    // - - - EXTERNAL DECLARATION  - - - - - - - - - - - - - - - - - - - - - - - - -

    extern sDefTst_Struct           g_sStruct;                      ///< Porte externe au fichier
5.1.1.3.1.4. Test

Dans les fichiers de test il ny a pas vraiment dimplmentation de fonction, mais un plan de test ou un excuteur de test. Voir la documentation de la couche TST dEGOS.

    // - - - TEST DECLARATION  - - - - - - - - - - - - - - - - - - - - - - - - - - -

    mTST_FIXT_START(...)
       ...
    mTST_FIXT_END()

Limplmentation de chaque test doit tre signifie comme suit.

    // - - - TEST IMPLEMENTATION - - - - - - - - - - - - - - - - - - - - - - - - - -

    mTST_CASE_FUNC(..., ...)
    ...
    mTST_ASSERT(...)

5.1.1.3.2. Documentation

Une partie de la documentation est gnre par un outil propritaire partir du code source C/C++. Cet outil est fortement inspir des rgles de documentation Doxygen. Vous pouvez trouver ci-dessous quelques rgles et exemples de documentation Doxygen.

Les blocs de commentaires Doxygen sont disponibles ici :

Identification des blocs de commentaire Doxygen
SectionDescription
\file Documentation dun fichier
\fn Documentation dune fonction
\var Documentation dune variable (numrique, pointeur, enum, structure, union, )
\def Documentation dun #define
\enum Documentation dune enumeration
\struct Documentation dune structure
\union Documentation dune union

La liste des commandes spciales de Doxygen est disponible ici :

Exemple dentres dun bloc de commentaire Doxygen
Section Description
\brief Explication
\warning Ajoute un warning
\details Ajoute des dtails
\param[in] Documentation dun paramtre d'entre
\param[out] Documentation dun paramtre de sortie
\param[inout] Documentation dun paramtre d'entre / sortie

En utilisant les rgles Doxygen, lcriture dun bloc de documentation peut tre crite de cette faon :

    ///
    /// \file                       pour documenter un fichier
    /// \fn                         pour documenter une fonction
    /// \var                        pour documenter une variable ou typedef ou valeur enum
    /// \def                        pour documenter un #define
    /// \enum                       pour documenter une enumeration
    /// \struct                     pour documenter une structure C
    /// \union                      pour documenter une union
    ///
  • Quelques lments Doxygen sont obligatoires, les autres facultatifs
5.1.1.3.2.1. Entête de fichier

Lentte de fichier est situ dans chaque fichier source. Il procure au lecteur / dveloppeur des informations propos de lentreprise, du projet, du produit, ... La plupart des champs sont optionnels et ne sont donns ici qu titre dinformations.

Composition de lentte de fichier
Section Description
Nom Le nom du fichier doit tre rappel pour viter les confusions et dtecter les renommages
Usage Une brve explication de la fonctionnalit
Projet Un code projet identifie un produit en interne avant quil nacquire un nom public
Produit Le nom public du produit
Modle Un produit peut tre dclin en plusieurs modles. Une information sur la variante
Cible Certains fichiers sont dpendants du matriel ou de certaines librairies.
Auteur Lauteur original qui servira de rfrent
Date Date de cration et de modification pour donner une ide de son re
Entreprise Lentreprise dorigine, qui peut tre revendue. Il est intressant de pouvoir tracer cette volution
Licence Licence sous laquelle est diffus le code source
    ///
    /// \file               ce_fichier.h
    /// \brief              Ce fichier fait cela
    /// \details    Et plein dautres choses
    /// \pre                Mais vous devez faire ceci dabord
    /// \bug                Sinon vous risquez davoir des problmes
    /// \note               Prenez note de a
    /// \remark             Cest optionnel
    /// \warning    Attention aux bugs
    /// \see                Se rfrer  la documentation
    /// \todo               Reste  faire
    /// \product    EGOS
    /// \author             Author / Author@company.com
    /// \date               2013/11/21
    /// \version    1.00
    /// \company    ERTOSGENER
    /// \site               Beaucouz
    /// \copyright  See license below
    ///
    /// \section    LICENSE
    ///
    /// Start of the Copyright Notice \n
    /// =========================================================================== \n
    /// === Copyright ERTOSGENER  ZEKAT                                                                            === \n
    /// === This computer program includes confidential proprietary information     === \n
    /// === and is a trade secret of ERTOSGENER. All use, disclosures and/or        === \n
    /// === reproduction is prohibited unless authorized in writing.                        === \n
    /// === All Rights Reserved                                                                                                     === \n
    /// =========================================================================== \n
    /// End of the Copyright Notice \n
    /// \n
    ///
  • Il peut y avoir plusieurs auteurs et dates par entte, en fonction des modifications apportes
5.1.1.3.2.2. Entête de fonction

Lentte de fonction est situ dans le fichier dentte h. Les informations fournies sont globalement les mmes, avec en plus des informations complmentaires concernant le dtail de limplmentation.

Composition de lentte de fonction
Section Description
But Le but gnral de la fonction
Paramtres Informations propos de la valeur de retour, les paramtres dentres et de sorties comme les types de donnes, plages de valeurs, codes derreur
Prconditions La liste des conditions ncessaires runir pour lexcution de la fonction
Pseudo code Un pseudocode lger dcrivant le fonctionnement de la fonction avec un lien vers le document de conception
Documentation Les commentaires lintrieur de la fonction doivent expliquer comment les choses fonctionnent. Le pourquoi doit se trouver dans le document de conception
Dsambiguation Des cls de reprage entre le pseudocode et le code doivent permettre au lecteur / dveloppeur de se reprer travers la fonction
Edition Auteur, date et raison de ldition
    ///
    /// \fn                 CetteFonction
    /// \brief              Cette fonction fait a
    /// \details    Et plein dautres choses
    /// \pre                Mais vous devez faire ceci dabord
    /// \bug                Sinon vous risquez davoir des problmes
    /// \note               Prenez note de a
    /// \remark             Cest optionnel
    /// \attention  Prcaution  prendre
    /// \warning    Attention aux bugs
    /// \exception  Objet dexception
    /// \param[in]  param1 Fait ceci
    /// \param[out] param2 Fait cela
    /// \return             Retour est de retour
    /// \retval             0 Valeur de retour quand nul
    /// \retval             1 Valeur de retour quand 1
    /// \see                Se rfrer  la documentation
    /// \todo               Reste  faire
    /// \author             Author / Author@company.com
    /// \date               2018/02/26
    /// \version    1.00
    ///
  • Il peut y avoir plusieurs auteurs et dates par entte, en fonction des modifications apportes
  • Certains champs sont optionnels et adapter au contexte (\pre \bug \note \remark \eception \see \todo)
5.1.1.3.2.3. Corps de la fonction

Le corps de la mthode est situ dans le fichier source .c. Il peut contenir davantages dinformations qui peuvent tre extraites par le gnrateur de la documentation.

    /// === 1. Bref commentaire
    /// === 1.1. Sous-commentaire
  • Mettre lentte de fonction dans le fichier dentte h afin dtre potentiellement diffusable
  • Mettre une entte de fonction allge dans le fichier source c mais ajouter du pseudo-code
  • Utiliser des balises didentification (A, A.B, ou 1, 1.1, ) pour chaque ligne de pseudo-code
  • Dans le dveloppement de la fonction, ajouter des commentaires faisant rfrence au pseudo-code

5.1.1.3.3. Lisibilité

La lisibilit gnrale dun code source dpend largement de lutilisation de passage la ligne des endroits spcifiques.

Une mthodologie employe dans le dveloppement dEGOS est lcriture verticale qui permet dallger la composition des lignes de code (moins dlments reprer par ligne), de visuellement reprsenter la structure du code et aussi de mieux pouvoir reprer les modifications lors dune comparaison fichier par fichier.

Le but principal est dviter au lecteur de fractionner mentalement de grands blocs de code pour en comprendre la structure et/ou hirarchie. Une indentation intelligente et lclatement des structures complexes procurent une aide visuelle qui rend la lecture plus confortable.

  • Lcriture se fait en vertical, la mode assembleur, chaque instruction spare par un passage la ligne
  • La lecture se fait simplement en suivant la crte des vagues gauche (dclaration, affectation, appel de fonction, ...) de profondeur limite, sans avoir se perdre sur des lignes de grande longueur et de gros blocs
  • Eviter de dpasser la limite de caractre dfinie pour le projet EGOS (120 car/ligne)
  • Un caractre de ponctuation (virgule ,, point-virgule ; ou point .) est toujours suivi dun espace
  • Par exemple en sparation dargument ou lments, sauf en cas de fin de ligne ou daccs des membres
5.1.1.3.3.1. Caractère d’indentation

Le caractre dindentation peut tre soir une tabulation ou un espace. La tabulation horizontale remplace un certain nombre de caractres espace, suivant le paramtrage de lditeur utilis. Pour le projet EGOS, le caractre dindentation slectionn est la tabulation.

Les avantages de la tabulation sur lespace est la facilit de changer le nombre de caractres despacement dans lditeur de code, le nombre de caractres despacements conomiss et le respect de lalignement (par pas de 4 caractres) lorsque des lignes sont commentes.

Linconvnient est le manque duniformisation de laffichage du code source si diffrents dveloppeurs choisissent un nombre despaces reprsentatifs diffrents.

  • Le caractre dindentation est la tabulation
  • Le nombre despacement reprsentatif de lindentation est de 4
5.1.1.3.3.2. Nombre d’indentation

Un nombre dindentation homogne travers un fichier permet dviter une trop grande diversit visuelle en fonction de lauteur, permet de garder les lments aligns et donc reprables facilement.

    // Colonne
    //      5       9       13      17      21      25      29      33      37      41      45      49      53

    /// \file               ce_fichier.h

    nS32                            (def_tst_Func)(nS32 i_nParam);

    DECL_TYPEDEF(struct, sDefTst_Tata)
    { nU32                                  nTiti
    ; struct
            { nU32                                  nToto
            ;}                                      sTutu
    ;}      DECL_INSTANCE(sDefTst_Tata);

    /// \fn                 def_tst_Func
    nS32 (def_tst_Func)
    ( nS32  i_nParam        ///< Juste aprs le paramtre, le type du paramtre dtermine la colonne
    )
    {
            for (...)
            // Sous la boucle
            {
                    ...;

                    if (condition1)
                    // Sous la condition
                    {
                            ...;
                    }
                    else if (conditon2)
                    // Sous la condition
                    {
                            ...;
                    }
                    else
                    // Sous la condition
                    {
                            ...;
                    }
            } // for
    } // for

    #define mDEF_TST__MACRO(val)
                             (val * cDEF_TST__VALUE)
  • Les commentaires (///) sont tout gauche
  • Les commentaires de section (/// \xx) sont tout gauche
  • Les commentaires C (//) sont la suite de la ligne de code
  • Limplmentation dune fonction est tout gauche
  • Les oprateurs, lignes de code suivent une indentation hirarchie
  • Les lments structurels ouvrants/fermants (parenthse, accolade, crochet) sont sur la mme ligne/colonne
5.1.1.3.3.3. Commentaires

Les commentaires sont aussi importants que le code source, car le code est une interprtation et une implmentation propre au dveloppeur de la spcification. Les commentaires doivent permettre de faire le lien entre le code source, la conception, la spcification, et mettre en lumire les dtails et les choix effectus. Il existe deux types de commentaires : langage C (/* */) et C++ (//)

    /* commentaire C */
    // commentaire C++

Pour des questions dhomognit, les commentaires doivent tre crits au format C++ (//).

  • Option 1, prfrer :
    /// Commentaire seul sur une ligne
    nS32    i_nNumero1;             ///< Commentaire aprs quelque chose, noter le <
  • Option 2 :
    //! Commentaire seul sur une ligne
    nS32    i_nNumero2;             //!< Commentaire aprs quelque chose, noter le !<

En utilisant les commentaires au format C++, il est plus facile didentifier et/ou filtrer ces commentaires au besoin.

Utiliser un motif commun tous les commentaires inutiles est compos dau moins 3 signes gal (===) pour viter de le confondre avec loprateur de comparaison (==) et dassignation (=). Cela peut tre utilis par des outils danalyse comme Vera++ et/ou CodeSonar afin de filtrer ces commentaires et dobtenir des statistiques plus prcises.

Quand on dit que ces commentaires sont inutiles cest parce quils servent quasi exclusivement la structure visuelle du code source, mais pas expliquer le fonctionnement du dit code. En fonction des besoins danalyse il peut tre aisment filtr hors du rapport code source / commentaire.

    // === Commentaire inutile qui peut facilement tre filtr
  • Utiliser le format de commentaire C++ (//)
  • Ne pas mettre de commentaire C++ (//) sur la mme ligne dun #define (risque dtre mal interprt)
  • Prfrer le positionnement du commentaire sur la ligne prcdente plutt qu la fin de ligne commenter
  • Utiliser le commentaire bon escient (ide de haut niveau, ne pas simplement redire ce qui est fait)
  • Ajouter de nombreuses rfrences la documentation, la conception voire la spcification
  • En cas de long commentaire pouvant servir de documentation, terminer les lignes par un point
  • En cas dextraction de ces longs commentaires, il est plus facile de les mettre en page comme phrases
  • Utiliser les balises FIXME ( corriger) et TODO ( faire) pour filtrage depuis lditeur de code (ex. Eclipse)
5.1.1.3.3.4. Alignement des crochets - accolades - parenthèses

Ce domaine est sujet controverses. Kernighan et Ritchie, qui ont cr le langage C, avaient une faon trs particulire de dvelopper hrite des prcdents langages de programmation. Les accolades ouvrantes et fermantes ntaient pas positionnes sur la mme colonne, comme en Java. Cependant il est difficile de trouver le dbut dun bloc si dautres blocs de mme hirarchie utilisent la mme syntaxe.

Toujours ajouter un espace avant une parenthse ouvrante et aprs une parenthse fermante (sauf en fin de ligne). En arant le code sur plusieurs lignes, il est plus facile de reprer quelle accolade ouvrante correspond quelle accolade fermante.

    for (...)
    {
            ...;

            if (condition1)
            {
                    ...;
            }
            else if (conditon2)
            {
                    ...;
            }
            else
            {
                    ...;
            }
    } // for
  • Un crochet fermant ] doit se trouver sur la mme colonne que le crochet ouvrant '\[ associ
  • Une accolade fermante } doit se trouver sur la mme colonne que laccolade ouvrante '{' associe
  • Une parenthse fermante ) doit se trouver sur la mme colonne que la parenthse ouvrante ( associe
  • Une parenthse ouvrante ( est prcde dun espace si un oprateur C (if, for, while, ) la prcde
  • Une parenthse ouvrante ( nest pas prcde dun espace si une fonction ou une macro la prcde
5.1.1.3.3.5. Prototype, implémentation, appel de fonction

Le prototype dune fonction dans un fichier dentte h est toujours sur une seule ligne, sauf en cas de fonction inline. En revanche lcriture de limplmentation dans le fichier c est toujours rdig avec un argument par ligne.

  • Fichier h, prototype :
    nS32                    (def_tst_FileCreate)(nS32 i_nParam1, nS16 i_nParam2, nS8 i_nParam3);
  • Fichier c, implmentation :
    __STATIC
    nS32 (def_tst__PortOpen)                        // Deux _ indiquent une fonction statique
    ( nS32          i_nParam1                       ///< Explication
    , nS16          i_nParam2                       ///< Explication
    )
    {
            ...;
    }

    nS32 (def_tst_FileCreate)
    ( nS32          i_nParam1                       ///< Explication
    , nS16          i_nParam2                       ///< Explication
    , nS8           i_nParam3                       ///< Explication
    )
    {
            nS32    l_nResult;

            ...;

            // But de lappel de fonction
            l_nResult
            =       (def_tst__PortOpen)
                    ( i_nParam1                     // Explication ventuelle
                    , i_nParam2
                    );

            l_nResult
            = (nS32)                                // Casting au format C
                    (def_tst__PortOpen)
                    ( i_nParam1
                    , i_nParam2
                    );
    }
  • Le nom dune fonction est crit entre parenthses pour la diffrencier dune macro avec le mme nom
  • Le nom dune fonction commence par la couche et le module voire la fonction crit en snake_case
  • En cas de fonction extern, utiliser un seul _ en sparation de la couche et de fonction implmente
  • En cas de fonction static, utiliser deux _ en sparation de la couche et de fonction implmente
  • Le nom de la fonction implmente est crit en anglais et en PascalCase (FileCreate, PortOpen)
  • Le nom dune fonction est crit en notation hongroise, fonctionnalit gnrique en premier, puis spcificit
  • Le fichier prototype h tout comme limplmentation c dclarent et nomment tous les paramtres (param1, param2, param3) pas juste des types (nS32, nS16, nS8)
  • Le fichier prototype h dclare les fonctions dans le mme ordre que dans limplmentation c
  • Les fonctions statiques dune implmentation sont situes en dbut de fichier c (voir les sections)
  • Dans le fichier dimplmentation c, aligner les paramtres gauche en commenant par la virgule ,
  • Dans le fichier dimplmentation c, aligner les paramtres entre eux en fonction de celui le plus droite
  • Si possible clater les appels de fonction, les calculs sur plusieurs ligne (comprhension, comparaison)
5.1.1.3.3.6. Conditions et/ou calculs complexes

Certains calculs complexes peuvent tre diviss en lments plus simples afin dviter davoir un bloc de texte illisible. Cela permet aussi dviter davoir des lignes trop longues en les coupant par des passages la ligne.

  • Option 1 :

Si le nombre de conditions nest pas suprieure trois, ou que la ligne est suffisamment courte.

    if ( (1 > condition1) || ( (2 < condition2) && (4 == condition3) ) )
  • Option 2, prfrer :

La hirarchie peut tre rendue apparente par lusage dindentation. Utiliser les parenthses et/ou les oprations logiques pour passer la ligne.

    if
    (       (1 > condition1)                                // Explication simple du test
    ||      (       (2 <    condition2)                     // Explication simple du test
            &&      (4 ==   condition3)                     // Explication simple du test
            )
    )
  • Eclater les conditions ou calculs complexes (plus de trois niveaux) et les indenter
  • Placer les constantes en premier dans les comparaisons

5.1.1.3.4. Structure du code

La structure du code est trs importante afin daider le dveloppeur et/ou le re/lecteur maintenir et reprer les fonctionnalits.

5.1.1.3.4.1. if / else

Loprateur if / else est utilis pour excuter deux branches de code en fonction dune condition slective. Loprateur else est optionnel, mais pour des questions de lisibilit, il est recommand de lajouter mme sil nest pas (encore) utilis.

Toujours utiliser les accolades aprs un else afin de marquer le bloc de code associ, mme vide.

    if (condition1)
    // Explication simple de condition1 (par ex. fichier ouvert)
    {
            ...;
    }
    else if (condition2)
    // Explication simple de condition2 (par ex. fichier ferm)
    {
            (...;)
    }
    else
    // Explication simple de condition par dfaut (par ex. signaler erreur)
    {
            (...;)
    }
  • Un if est toujours accompagn dun else correspondant, mme vide
  • En cas de construction if / else if / else if toujours ajouter un else final, mme vide
  • Un if est toujours entour daccolades, mme pour une seule instruction, ou vide
  • Un else est toujours entour daccolades, mme pour une seule instruction, ou vide
  • Ecrire les constantes en premier dans les conditions (TRUE == test()) pour viter lassignation (en effet, le compilateur dtecte une tentative dassignation dune constante (TRUE = test()) mais pas linverse)
  • La condition dun if est toujours explicite (TRUE == test()) et jamais implicite (test())
  • Ne pas effectuer de sortie anticipe (exit, break, continue, goto) dans un if / else, utiliser les conditions de sortie
  • La sortie anticipe break est autorise uniquement dans le cas d'un switch / case, voir ci-dessous.
5.1.1.3.4.2. goto

Loprateur goto est interdit en MISRA, bien quil pourrait tre utile dans certains cas trs prcis et donc justifis en consquence. Utiliser des alternatives connues et comprhensives par des outils danalyse de code.

  • Lutilisation de goto est interdite, utiliser plutt une construction do { break; } while (0)
  • Si lutilisation de goto semble absolument requise, revoir larchitecture du code devant y faire appel
  • Lutilisation de setjmp / longjmp est interdite en dehors dun ordonnanceur
5.1.1.3.4.3. switch / case / break / default

Un slecteur switch-case fonctionne uniquement sur des valeurs numriques entires (entier, enum) dans le langage C/C++. Il permet dexcuter diffrentes portions de code en fonction de la valeur dentre. Il est conseill de lutiliser plutt quun enchainement doprateurs if / else if / else si la condition tester est de type adapt.

Loprateur break permet de sortir du slecteur switch-case.

Encadrer avec des accolades chaque case dans un sous contexte indpendant. Le terminer par un break.

Il est possible denchainer plusieurs case, dun cas de dpart jusqu un cas darrive, en ne faisant pas appel loprateur break entre eux. Certains compilateurs ncessitent cependant une confirmation explicite de ce comportement attendu. En cas de besoins, utiliser la macro __FALLTHRU qui implmente cette spcificit.

Loprateur default est obligatoire.

    switch (selector)
    // Explication claire de la slection (par ex. type de fichier)
    {
            case 1:
            // Explication simple du cas 1 (par ex. fichier image PNG)
            {
                    ...;
            }       break;
            case 2, 3:              //  viter, les sparer un par ligne
            case 4:
            {
                    ...;
            }       break;
            case 5:
            {
                    ...;
            } __FALLTHRU
            case 6:
            {
                    ...;
            } __FALLTHRU
            default:
            // Explication simple du cas par dfaut (par ex. signaler type non reconnu)
            {
                    ...;
            }       break;
    } // switch

Lindentation est importante afin de reprer rapidement les oprateurs case et default qui doit toujours tre positionn en dernier.

  • Un case doit toujours se terminer par un break sauf en cas denchainement
  • Un switch doit toujours se terminer par un default, mme vide, suivi dun break
  • Utiliser le default pour traiter le cas gnrique, voire renvoyer une erreur si non prvu
  • Eviter les case qui se suivent et excutent le mme code (2,3 et 4) revoir la conception pour les distinguer
  • Si impossible de distinguer les case car rpondant la mme fonction, les sparer un par ligne
  • Commenter laccolade fermante du slecteur switch avec // switch pour en comprendre lorigine
5.1.1.3.4.4. for

La boucle for est utilise en gnrale pour travailler sur des tableaux. Elle ncessite trois lments pour travailler : une initialisation, une condition de fin et un modificateur.

Pour rappel, lordre dvaluation est toujours: initialisation (1x), condition, boucle, modificateur, condition, boucle,

    for
    ( init                                                  // Explication simple de la condition
    ; limit                                                 // Explication simple de la condition
    ; modif                                                 // Explication simple de la condition
    )
    // Explication simple des lments utiliss (par ex. chaque fichier du rpertoire)
    {
            ...;

            ...;
    } // for
  • La dclaration des variables utilises sont effectues lextrieur de la boucle for
  • Une boucle doit tre courte et sexcuter rapidement pour ne pas perturber le fonctionnement du reste du logiciel
  • Une boucle for est toujours entoure daccolades, mme pour une seule instruction, ou vide (boucle infinie)
  • Commenter laccolade fermante de la boucle for avec // for pour en comprendre lorigine
  • Chaque condition init, limit et modif peuvent contenir plusieurs expressions spares par des virgules ,
  • Prfrer lcriture des conditions sur plusieurs lignes afin de pouvoir ventuellement les commenter
  • Utiliser la condition init pour initialiser les variables ncessaires au fonctionnement de la boucle for
  • En gnral une boucle for est incrmentale, cest--dire commence de 0 et va vers la fin/le maximum
  • Une boucle for dcrmentale permet de gagner un test car 0 le dcrment positionne dj le flag Zero
  • Si possible, utiliser une diffrence (, >=) comme condition limit en cas dincohrence de valeur
  • Si utilisation de nombre flottant, toujours utiliser une diffrence (, >=) comme condition de fin limit
  • Si possible, utiliser au moins une deuxime condition limit comme garde-fou (taille du tableau, timeout, ...)
  • Eviter si possible toute sortie anticipe (exit, break, continue, goto) mais utiliser la condition limit
5.1.1.3.4.5. while – do / while

La boucle while existe en deux versions, une vrifiant la condition de sortie dabord, lautre aprs avoir excut au moins une fois le corps de la boucle avant de tester la condition de sortie do / while.

  • Option 1 : La vrification de la condition de sortie avant la premire excution est effectue avec la boucle while.
    while (condition)
    // Explication simple de la condition (par ex. fichier existe)
    {
            ...;
            ...;
    } // while
  • Option 2 : La vrification aprs une premire excution est effectue avec la boucle do / while.
    do
    {
            ...;
            ...;
    }
    // Explication simple de la condition (par ex. fichier existe)
    while (condition)
  • La dclaration des variables utilises sont effectues lextrieure de la boucle while
  • Une boucle doit tre courte et sexcuter rapidement pour ne pas perturber le fonctionnement du reste du logiciel
  • Une boucle while est toujours entoure daccolades, mme pour une seule instruction, ou vide (boucle infinie)
  • Commenter laccolade fermante de la boucle while avec // while pour en comprendre lorigine
  • Prfrer lcriture de la condition sur plusieurs lignes afin de pouvoir ventuellement les commenter
  • Si possible, utiliser une diffrence (, >=) comme condition en cas dincohrence de valeur
  • Si utilisation de nombre flottant, toujours utiliser une diffrence (, >=) comme condition
  • Si possible, utiliser au moins une deuxime condition comme garde-fou (taille du tableau, timeout, )
  • Eviter si possible toute sortie anticipe (exit, break, continue, goto) mais sparer avec une condition if
  • Eviter si possible toute sortie anticipe (exit, break, continue, goto) mais utiliser la condition de sortie
5.1.1.3.4.6. Opérateurs

Le langage C dispose dune prcdence des oprateurs logiques et arithmtiques. Il est possible de forcer la prcdence doprateurs sur dautres par lusage de parenthses.

Prcdence des oprateurs en langage C
PrcdenceOprateurDescriptionAssociativit
1()Parenthese grouping (evaluated from inner to outer)Left-to-right
()Function callLeft-to-right
[]Array subscriptingLeft-to-right
.Structure and union member direct accessLeft-to-right
->Structure and union member pointer accessLeft-to-right
(type){list}Compound literal (C99)Left-to-right
++, --Suffix/postfix increment and decrement respectively (i++, i--)Left-to-right
2++, --Prefix increment and decrement respectively (++i, --i)Right-to-left
+, -Unary plus and minus respectivelyRight-to-left
!, ~Logical NOT and bitwise NOT respectivelyRight-to-left
(type)Type cast (C)Right-to-left
*Indirection (*i dereference)Right-to-left
&Address-of (&i)Right-to-left
sizeofSize-of a data type or variable (no casting involved)Right-to-left
_AlignofAlignment requirement(C11)Right-to-left
3*, /, %Multiplication, division and remainder respectivelyLeft-to-right
4+, -Addition and subtraction respectivelyLeft-to-right
5<>Bitwise left shift and right shift respectivelyLeft-to-right
6For relational operators < and respectivelyLeft-to-right
>, >=For relational operators > and respectivelyLeft-to-right
7Err :510For relational = and respectivelyLeft-to-right
8&Bitwise ANDLeft-to-right
9^Bitwise XOR (exclusive or)Left-to-right
10|Bitwise OR (inclusive or)Left-to-right
11&&Logical ANDLeft-to-right
12||Logical ORLeft-to-right
13?:Ternary conditionalRight-to-Left
14=Simple assignmentRight-to-Left
+=, -=Assignment by sum and difference respectivelyRight-to-Left
*=, /=, %=Assignment by product, quotient and remainder respectivelyRight-to-Left
<<=, >>=Assignment by bitwise left shift and right shift respectivelyRight-to-Left
&=, ^=, |=Assignment by bitwise AND, XOR and OR respectivelyRight-to-Left
15,CommaLeft-to-right
  • Utiliser si possible des parenthses pour bien prciser la priorit et prcdence attendue
  • Ne pas faire confiance la prcdence des oprateurs unaire (++, -- car prcdence 1 ou 2)
  • Utiliser plutt une affectation arithmtique de faible prcdence (+=, -= de prcdence 14)
  • Eviter dutiliser loprateur unaire ++ ou pour modifier une variable, utiliser plutt += 1 ou -= 1
  • Eviter si possible la comparaison ternaire (cond) ? (if true) : (if false) sauf l o cela se justifie vraiment
  • Ne pas utiliser lindex [-1] dun tableau pour obtenir sa taille, car dpendant de certains compilateurs
  • Vrifier la valeur dun diviseur avant de lutiliser dans une division ou un modulo
  • Faire attention la prcdence des modificateurs volatile et constant (pcnData vs. cpnPointer)

5.1.1.3.5. Configuration

Lors du dveloppement logiciel, certains changements bass sur des dcouvertes empiriques ncessitent de modifier le code de faon temporaire. Il peut aussi y avoir diffrentes configurations de compilations pour saccommoder de diffrents besoins, comme le dverminage, la libration ou le test.

5.1.1.3.5.1. Compilation conditionnelle

La compilation conditionnelle utilise le prprocesseur pour ds/activer certaines portions du code source. Certaines compilations conditionnelles peuvent tre incluses dans dautres compilations conditionnelles. Une indentation additionnelle pour montrer limbrication des conditions nest pas requise mais peut rendre le code plus lisible.

    #if defined(dCONDITION)
            ...;                            // Code excut sous dCONDITION
    #else   // defined(dCONDITION)
            ...;                            // Code alternatif
    #endif  // defined(dCONDITION)

Il est souhaitable de commenter chaque #elif, #else et #endif avec leur condition respective. Il est ainsi plus facile de distinguer quel bloc appartient quelle condition.

  • Un #if doit toujours tre accompagn dun #endif correspondant
  • Pour chaque condition #elif, #else ou #endif, ajouter en commentaire la condition associe
  • Prfrer lutilisation de #if defined(x) #ifdef (x) car plus facile composer avec des oprations boolennes ou des conditions arithmtiques (x >= 3)
5.1.1.3.5.2. Mise en commentaire

Mettre une section de code en commentaire seffectue exclusivement par lusage de #if 0 / #endif qui inclus toute instruction et/ou bloc de commentaire.

    #if 0
            ...;                            // Code dsactiv et non excut
    #endif  // 0

Certains diteurs de code procurent des raccourcis (Eclipse = [Ctrl]+[Shift]+[/]) pour d/commenter les lignes slectionnes au format C++ (//). Cependant il nest pas recommand dutiliser cette mthode en-dehors dun test ponctuel. Si le code doit tre activ dans un certain contexte, utiliser la compilation conditionnelle en isolant les instructions sous une ou plusieurs conditions.

  • Isoler du code dsactiver entre un couple #if 0 / #endif plutt que de le commenter
  • Ne pas laisser de code mort dans le code final, nettoyer ou transformer en code alternatif si pertinent

5.1.1.4. Règles de codage

Lutilisation des fonctionnalits tendues du langage C++ (exceptions, templates, ) est fortement dconseille non seulement du fait de la faible maitrise gnrale des dveloppeurs de ces fonctionnalits, car en gnral propre au C++ mais aussi trs difficile apprhender, mais aussi du fait de la puissance/mmoire limite des compilateurs et/ou des cible supportes par EGOS.

5.1.1.4.1. Allocation mémoire

La rservation de bloc mmoire est ncessaire sous EGOS pour pouvoir tracer les allocations de ressources.

  • Lallocation dynamique de mmoire est obligatoire (malloc/free, new/delete, )
  • Lutilisation de la pile pour allouer des tableaux temporaires est contrler soigneusement
  • Interdiction de dclarer des variables globales, utiliser le chest dun processus ou thread EGOS
  • Interdiction dutiliser le fichier de mapping mmoire pour rserver des blocs de mmoire statiques

5.1.1.4.2. Casting

Les casting de donnes et/ou de pointeur doivent tre vits car ils rvlent une mauvaise conception et/ou un mauvais usage du polymorphisme. La syntaxe au format C (entre parenthses) est privilgier.

    const_cast<type>                // Supprime lattribut const dun objet, dangereux
    static_cast<type>               // Conversion entre types similaires, quivalent au cast langage C
    reinterpret_cast<type>  // Conversion entre diffrents types de pointeur
  • Utiliser le casting au format du langage C (entre parenthses)
  • Spcifier systmatiquement le format du casting au besoin, ne pas laisser le compilateur interprter