Un bon programme doit:

·         “marcher”: fait ce qu’il est supposé de faire (donc avoir été bien testé - vois ici bas "Comment tester un programme C".

·         Etre Lisible : claire et simple à lire. Ceci rend la maintenance (modification du programme en raison de correction d’erreurs ou de changement/ajout de fonctionalités) du programme plus simple. La lisibilité d’un programme est un facteur trés important.

·         Etre Simple : la solution adoptée doit être simple, ne pas essayer de compliquer les choses.

·         Etre Efficace : en termes de temps d’execution et d’espace mémoire utilisé.

·         Etre Modulaire : Le programme devrait être structuré en modules, chaque module accomplissant une tâche distincte. Chaque module contenant une ou plusieurs fonctions, où chaque fonction accomplit à son tour des actions spécifiques. 

·         Etre Extensible : essayer d’écrire les fonctions du programme les plus générales possible de façon à ce qu’elles soient réeutilisables.

 

Ci-dessous plus de détails sont donnés en ce qui concerne la lisibilté d’un programme. Aussi certains points importants à vérifier lorsqu’un programme est écrit en C sont décrits.

 

Lisibilité dún Programme

Certaines règles doivent être adoptées :

·       -- Les variables (et les constantes aussi) doivent avoir un nom significatif, c’est-à-dire donner un nom à chaque variable selon à quoi elle sert.

·       -- De la même façon les fonctions doivent avoir un nom significatif.

·       -- Ne pas écrire des fonctions trop longues (plusieurs centaines de lignes de code) car cela rendrait la lisibilté plus difficile.

·       -- Ne pas hesiter à ajouter des commentaires pour expliquer ce que fait le code, et en particulier chaque fonction devrait commencer par un commentaire expliquant ce que fait la fonction et le rôle de chacun des paramètres de la fonction.

·      -- Ne pas ecrire plus d'une instruction par ligne.

       Exemple:

          i=a+b;j=a*b;k=a-b;            /* mauvaise lisibilite */

 

          i = a + b;                             /* meilleur lisibilite */

          j = a * b;

          k = a - b;

·       -- Ajouter des éspaces dans les expressions, affectations...

      Par exemple:

      x=(y*z)+1;    /* mauvaise lisibilite */

 

      x  =  (y * z) + 1;  /* meilleur lisibilite */

·       -- Bien indenter les structures de contrôle du programme (if/else, for, while, do while, switch …)

 

Par exemple la fonction c-dessous n’est pas bien indentée :

int absolue(int n)
{
int abs;
if (n < 0)
abs = n;
else
abs = -n;
return abs ;
}

La même fonction bien indentée :

int absolue(int n)
{
int abs;
   if (n < 0)
abs = n;
else
abs = -n;
   return abs;
}

 

Fonction mal indentée :

long factoriel(int n)
{
int i;
long fac = 1; 
for (i = 1; i <= n; i++)
fac = fac * i;
return fac;
}

La meme function bien indentée:

long factoriel(int n)
{
int i;
  long fac = 1; 
  for (i = 1; i <= n; i++)
fac = fac * i;
  return fac;
}

 Points Important à Verifier dans un Programme C

Ci-dessous sont décrit des points important à verifier lors de l’écriture d’un programme en C:

·        -- Compiler son programme après l'ajout de chaque fonction. Ne pas ajouter toutes les fonctions et ensuite compiler car il peut y avoir beaucoup d'erreurs de compilation et ca sera difficile de corriger toutes les erreurs.

·       --  Corriger les warnings (avertissements) donnés par le compilateur. C étant un langage souple pour ce qui est du contrôle des types (type checking) certains warnings donnés par le compilateur peuvent être des erreurs à l'execution s'ils ne sont pas corrigés à la compilation.

·       -- S'il y'a un problème à l'execution faire d'abord une inspection visuelle du code avant d'utiliser le debugger. Parfois il s'agit d'erreur facile à trouver en inspectant uniquement le code. Aussi il est toujours bon d'inspecter son code même s'il n'y a pas de problème à l'execution; l'inspection du code peut révéler d'eventuelles améliorations.

·       -- Comparer les paramètres réels et les paramètres formels des fonctions. Le type du paramètre formel doit être le même que celui du parametre réel. Verifier vos fonctions ainsi que l’appel des fonctions des libraries de C (stdio.h, string.h …). Comparer pour toutes les fonctions le type du résultat que la fonction retourne avec le type de la variable où la fonction retourne ce résultat.

·         Initialiser toutes les variables et en particulier les pointeurs.

·       -- Toute parenthèse/accolade ouvrante doit avoir sa correspondante parenthèse/accolade fermante.

·       -- Ne pas utiliser un indice de tableau plus grand que le nombre d’éléments du tableau. Ceci s’applique aux chaines de caractères aussi. Faites attention que l'indice d'un tableau en C commence de 0.

·       -- Ajouter des parenthèses dans les expressions compliquées pour éviter une possible erreur de précédence des opérateurs.

·       -- Verifier toutes le boucles. Voir comment la variable qui contrôle la boucle est initialisée : est-elle initialisée, est-elle initialisée à la bonne valeur. Voir comment cette variable est testée pour déterminer la fin de la boucle et en particulier est-ce qu’elle permet une itération de plus ou de moins. Voir aussi comment cette variable est modifiée à l’intérieur de la boucle : devrait être incrementée à la bonne valeur (éviter les boucles infinies).

·       -- Faites attention au faite que C est un langage case sensitive (minuscule et majuscule dans les identificateurs ne sont pas la même chose).

·       -- Faites attention au pointeur NULL. Un pointeur NULL pointe nul part en mémoire, donc ne pas référencer ce type de pointeur. Verifier que tous les pointeurs utilisés sont initialisés. Remarquer que si la variable pointeur est une variable globale elle est automatiquement initialisée à NULL mais si c’est une variable locale elle contient n’importe quoi au début.

·       -- Faites la différence entre ‘=’ et ‘==’ ; ‘=’ désigne une affectation alors que ‘==’ designe l'opérateur d’égalite. Si vous ecrivez par erreur ‘if (a=3) { …}’ alors a est affectée la valeur 3 et tout ce qui est entre ‘{ … }’ est executé tandis que si vous ecrivez ‘if (a==3) { …}’ alors ce qui est entre ‘{ … }’ est executé uniquement dans le cas où a est égale a 3.

·       -- Verifier que vous n’avez pas oublie un ‘break’ dans un ‘case’ à l’interieur d’un ‘switch’ (sauf si le 'break' a été omis de manière volontaire).

·       -- Si vous allouez de la mémoire verifier que vous liberez cette mémoire à un moment donné.

·       -- Faites attention au ‘ ;’ immediatement après un while() ou un for(). Un ‘ ;’ immediatement après un while() résulte en une boucle infinie, tandis qu’un ‘ ;’ immédiatement après un for() ne résulte pas en une boucle infinie mais c’est une erreur à l’execution.

·       -- Faites la différence entre ‘A’ et “A”. ‘A’ est le caractère A qui contient exactement un octet en mémoire tandis que “A” est la chaine de caractères “A” qui contient 2 octets en mémoire : le caractere A et le NULL caractère qui termine toutes les chaines de caractères.

 

Comment Tester un Programme C

Une étape importante dans la réalisation d'un programme (plus généralement de logiciel) est l'étape de test. Un programme doit être bien testé pour avoir une certaine confiance que notre programme "marche". Noter que l'on ne peut jamais garantir qu'un programme ne contient pas d'erreur pour la simple et bonne raison qu'on ne peut pas faire de test exhaustif. Donc on essaye d'avoir des tests qui ont une bonne couverture (coverage).

 

Il ne s'agit pas ici de présenter un cours sur le test de logiciel mais de donner quelques directives de tests bonnes a savoir.

- Un plan de tests (test plan) qui contient les cas de tests (test cases) à executer doit etre écrit au préalable. On peut utiliser un simple fichier texte pour celà. Apres éxecution de chaque cas de test il faut écrire le verdict (succés ou echec) de l'execution du test. La question qui se pose est comment générer ces cas de tests. 

Globalement il y'a 2 methodes de test: white-box testing et black-box testing. Dans le white box testing 

on analyse la structure interne du programme pour générer les cas de tests. Par exemple si on a un If-Then-Else on devra tester la condition où le If est vrai et tester la condition où le If est faux. Dans le cas du black-box testing les cas de tests sont généres à partir de l'enonce (la specification) du problème sans voir le code source du programme. Une combinaison des 2 méthodes peut être aussi utilisée.

 

Voici quelques une de ces directives:

- Tester chaque fonction à part (unit testing).

- Une fois que toutes les fonctions sont testées, tester chaque fonctionalité du programme (integration testing).

- Tester aussi bien les valeurs valides que les valeurs invalides. Pour les valeurs invalides il ne faut pas que le programme crash ou bien qu'il y'ait une boucle infinie - l'ideale dans ce cas est qu'un message d'erreur est affiché.

- Si une valeur numérique (entière) doit être comprise dans un intervalle [min, max], alors tester comme valeurs valides min, max, et une valeur entre min et max et comme valeurs invalides (min - 1), (max + 1), valeur < min et une valeur > max. Dépendemment ce que doit faire la fonction voir si on a besoin de tester des valeurs positives, negatives, zero, valeurs pairs, impairs, nombres premiers, nombres non premiers, ...

- Pour les chaines de caractères, utiliser comme caractères des lettres, des chiffres, des caractères speciaux, des espaces, des minscules, des majuscules.. Si la chaine de caractères a une taille limite tester la limite, plus petite que la limite, plus grande.que la limite.

- Si on utilise des fichiers, tester fichier existant avec donnés correct, avec des donnees incorrect (mauvaix format), fichier vide, fichier inexistant.

- Tester condition If-Then-Else condition vrai et condition fausse.

- Si la condition dans un If est une condition composée (avec des ET et des OU) tester toutes les combinaisons qui donnent la condition Vrai et toutes les combinaisons pour lesquelles la condition est fausse.

- Tester aussi tous les scénarios (conditions Vrai et conditions fausses) dans les Si imbriqués.

- Tester tous les case dans un switch statement

- Tester les boucles pour 0 iteration, 1 iteration et un nombre multiple d'iterations.

- Structure de Données(SD): Tester SD vide, SD avec 1 seul element, SD avec plusieurs éléments, SD pleine (si SD a une limite), ajout/suppression/modification 1er élément, élément au milieu, élément dernier. Tester éléments dupliques. 

- Pointeurs: pointeur nil, non nil, 2 ou plusieurs pointeurs qui pointent vers le meme objet.

 

Une chose qui arrive parfois après modification du programme pour corriger une erreur, est qu'une erreur est introduite et une chose qui marchait auparavant ne marche plus. Donc après correction des erreurs retester non seulement ce qui  a été corrige mais faire aussi d'autres tests (bien choisir les autres tests à faire aussi en fonction des changements fait). 

 

 

 

Langage C

Le document avec le lien ci-dessous est une bonne reference du langage C.

http://cslibrary.stanford.edu/101/EssentialC.pdf

 

Lorsqu’on programme dans n’importe quel langage il est trés important de bien connaitre ce langage et en particulier de connaitre certaines choses de façon à ne pas faire certaines erreurs qu’un débutant pourrait faire facilement. Le document ci-dessous décrit un certain nombre de ces choses bon à savoir sur le langage C.

http://www.literateprogramming.com/ctraps.pdf