Conseils de codage en C/Facilité de modification

Un programme est souvent amené à être modifié, adapté, réutilisé par celui qui l'a écrit ou par un autre, sur une longue durée (correction d'erreur, évolution du logiciel, réutilisation dans une autre application...).

Ces conseils visent à réduire les efforts nécessaires lors d'évolutions.

Éviter les constantes littérale (c_mod_1) modifier

Les constantes chaîne, numérique doivent être représentées par des symboles. Les constantes littérales sont interdites.

Justification modifier

Les constantes littérales dupliquées et réparties dans le code source rendent les modifications plus difficiles : risque d'altération, d'oubli d'une occurrence. Il faut les regrouper sous formes de constantes symboliques (définition du pré-processeurs) en tête de fichier source ou dans des fichiers inclus.

Exemple modifier

  • Mauvais : perimetre = 3.14159 * diametre;
  • Meilleur : #define PI 3.14159 ... perimetre = PI * diametre;

Écrire des commentaires fonctionnels (c_mod_2) modifier

Les commentaires ne doivent pas paraphraser le code, ils doivent expliquer la logique de traitement et justifier les choix effectués (pourquoi tel algorithme, telle structure de données, ...).

Justification modifier

La personne, qui relira le code source en vue de sa maintenance, aura besoin de comprendre les grandes étapes de l'algorithme, les fonctions réalisées par la suite d'instructions du langage.

Exemple modifier

Mauvais :

// Incrémentation de i
i = i + 1

Meilleur :

// Passage au fichier suivant
i = i + 1

Pas d'éléments inutiles ou non initialisés (c_mod_3) modifier

Toute fonction définie doit être utilisée et toute variable déclarée doit être initialisée.

Justification modifier

Évite la présence de code mort qui nuit à la maintenance.

La valeur par défaut d’une variable dépend de facteurs qui peuvent échapper au programmeur. Cette règle évite les fonctionnements aléatoires de certains programmes.

Outils modifier

Les compilateurs et les outils de vérifications statiques comme splint émettent des avertissements en cas de problème. Certains compilateurs possèdent des options pour générer tous les avertissements sous forme d'erreur, ce qui permet d'interrompre une chaîne de compilation afin de corriger le code.

Pas de duplication de code source (c_mod_4) modifier

Ne pas dupliquer de grandes parties de code dans plusieurs fichiers source.

Justification modifier

  • La duplication de source oblige à intervenir à plusieurs endroits pour corriger une erreur.
  • Rend le code source moins maintenable.
  • Lire plusieurs fois le même code ralentit sa compréhension.

Les parties dupliquées doivent être fusionnées en une seule. Le code commun, éventuellement paramétré, deviendra une fonction. Si des contraintes de performance l'impose, l'inlining pourra être utilisé.

Outils modifier

La recherche des parties dupliquées pourra se faire avec un outil de recherche de chaînes de caractères : sous UNIX grep ou à l'aide d'un éditeur s'il permet la recherche de texte dans plusieurs fichiers.

Limiter le nombre des variables externes ou globales (c_mod_5) modifier

L'utilisation de variables externes ou globales doit être limité au maximum.

Justification modifier

Les variables globales peuvent être modifiées par plusieurs unités de compilation, le contrôle des modifications est donc très délicat, les effets de bord sont possibles (modifications non désirées d'une variable ou d'une zone mémoire par du code lié). Un trop grand nombre de variables externes dénote une mauvaise analyse des interfaces entre unités de compilation ou une mauvaise gestion de la portée des variables.

Le mot-clé static en C permet, entre autres, de limiter la portées d'une variable globale ou d'une fonction à son seul fichier source. Il garantit que ces fonctions ou variables ne seront pas utilisées, par erreur, par d’autres unités. Les fonctions locales pourraient être masquées ou masquer d’autres fonctions de même nom, mais définies ailleurs dans le projet ou dans une bibliothèque liée. Le comportement du programme pourrait alors dépendre de l’ordre dans lequel les objets et bibliothèques sont présentés à l’édition de lien. Le respect de cette règle allégera l’édition de lien et évitera certains effets de bord.

Outils modifier

  • Recherche dans les fichiers sources des mots clés extern, des déclarations de variables hors des fonctions.
  • L'utilitaire Unix nm et ses options -g et -o permet de connaître les symboles externes dans les résultats de compilation (modules objets .o, bibliothèques .a, .so).

Ne pas réinventer la roue (c_mod_6) modifier

Utiliser les fonctions et bibliothèques écrites par d'autres programmeurs, principalement dans :

  • les bibliothèques standards du langage.
  • les bibliothèques de calcul numérique reconnues (LAPACK, LINPACK, BLAS).
  • tout autre développement suffisamment fiable.

Justification modifier

Le respect de ce conseil limite le nombre de lignes de code à maintenir ainsi que les efforts nécessaires aux tests du logiciel.

Limiter le nombre de sortie (c_mod_7) modifier

Une fonction ne devrait comporter qu'un seul point de sortie.

Justification modifier

Diminue la complexité du code et facilite l'analyse du déroulement du programme en mise au point.

Contrôle modifier

Rechercher des instructions return et exit à l'aide d'un utilitaire comme grep.

Évitez le type union (c_mod_8) modifier

L’utilisation du type union est déconseillé, sauf pour manipuler des champs de bits.

Justification modifier

Améliore la portabilité.

Pas de code dans les .h (c_mod_9) modifier

Ne jamais écrire de fonctions ou d'instructions dans les fichiers d’entête .h (excepté les macros instructions).

Justification modifier

Écrire le corps de fonction dans un fichier .h et l’inclure dans plusieurs sources dupliquerait ce code et pourrait provoquer des erreurs due aux symboles définis plusieurs fois. Plutôt que d’utiliser le pré-processeur, il faut répartir le code source dans différents fichiers .c qui seront compilés séparément et réunit lors de l’édition de lien.

Seuils pour les métriques déterminant la facilité de modification (c_mod_10) modifier

Les métriques suivantes influent sur la facilité de modification d'un programme (ISO/IEC 9126) :

  • AVGS : Taille moyenne des instructions, calculée à partir du nombre d'opérateurs et d'opérandes distincts.
  • LEVL : Nombre maximal d'imbrications des structures de contrôle (for, while, if...) de la fonction plus un.
  • VOCF : Fréquence d'utilisation du vocabulaire dans un composant, défini par la formule : F_VOC = (N1+N2)/ (n1+n2) avec :
    • N1 est le nombre d'occurrence des opérateurs,
    • N2 est le nombre d'occurrence des opérandes,
    • n1 est le nombre opérateurs distincts,
    • n2 est le nombre opérandes distincts.
  • CALL : Nombre d’appels distincts : Nombre total d'appels de fonctions effectués dans la fonction analysée.

Seuils pour les métriques :

  • AVGS : de 2 à 10
  • LEVL : de 1 à 5
  • VOCF : de 1 à 4
  • CALL : de 0 à 7

Justification modifier

  • AVGS : Les instructions trop longues sont difficiles à modifier. Elles peuvent provoquer des problèmes de priorité des opérateurs, des conversions de type involontaires.
  • LEVL : Un trop grand nombre d'imbrication de structures de contrôle pourra être une source d'erreur en cas de modification d'un programme. Il faut déplacer certains niveaux dans une fonction.
  • VOCF : Un vocabulaire qui se répète trop pourra être dû à des copiés-collés abusifs de parties de code ou à un programmeur à jeu d'instruction réduit. Les modifications à apporter devront alors s'appliquer à de nombreux endroits. Une solution consiste à factoriser le code à l'aide de fonction paramétrées ou à réutiliser du code externe développé et validé (bibliothèques spécifiques).
  • CALL : Une valeur trop élevée montre une mauvaise hiérarchisation dans la fonction. Un nombre élevé de fonctions appelée et de paramètres augmente le nombre de combinaisons possibles dans le déroulement du programme. Il faut limiter le nombre d'appel au besoin en découpant la fonction.