La première grande catégorie d'options de GCC est l'ajout de
warnings. Lorsque l'on rédige du code, il arrive que l'on fasse de petites erreurs d'inattention comme confondre les symboles
= et
== ou oublier d'initialiser une variable. Le code obtenu est souvent valide et le compilateur le traduit sans broncher. Par contre, le programme obtenu ne fait pas ce que l'on pensait et certaines erreurs sont difficiles à repérer. Le compilateur peut nous aider à repérer des instructions syntaxiquement valides, mais potentiellement erronées.
Le compilateur peut aussi nous aider à écrire du code entièrement conforme à la norme, ce qui devrait, en théorie, aider à porter le code d'une plate-forme à l'autre.
Je ne vais pas vous présenter tous les
warnings existants car il y en a bien trop, mais je vais vous parler des plus courants ou, en tout cas, de ceux que j'utilise régulièrement.
Les options de base
Pour simplifier la vie des utilisateurs, les concepteurs de GCC ont regroupé les
warnings les plus utiles dans ce que l'on pourrait appeler des
super-options. Celle que tout le monde utilise est
-Wall. Lorsque l'on active cette option, la plupart des erreurs courantes sont relevées et pourront ainsi être corrigées.
Par exemple, si l'on oublie un
return dans une fonction, le compilateur nous le dira. La fonction suivante ne prend pas en compte le cas
a==0, mais on ne le remarque pas forcément au premier coup d'œil. Le compilateur, lui, détectera cette erreur.
Code : C++ - fonction.cpp | int f(int a)
{
if(a<0)
return 2*a;
else if(a>0)
return 3*a;
}
|
Le message correspondant sera le suivant :
Code : Console | fonction.cpp: In function ‘int f(int)’:
fonction.cpp:7:1: warning: control reaches end of non-void function |
Ce qu'on peut traduire par : « Il est possible d'atteindre la fin d'une fonction qui ne renvoie pas
void ». Effectivement, si
a==0, on atteint l'accolade fermante sans avoir passé par un
return, ce qui est certainement une erreur.
Prenons un autre exemple classique, que j'ai repris du forum en le modifiant quelque peu :
Code : C++ - fonction2.cpp | int f(int a)
{
if(a=0)
return 2;
else
return 3;
}
|
Ce code est valide. Dans le
if, la valeur 0 est assignée à
a puis le test est effectué et, puisque la valeur est égale à 0, on passe toujours dans le
else. Au premier coup d'œil, on ne remarque pas forcément qu'il manque un
=. Le compilateur, lui, nous dit ceci :
Code : Console | fonction2.cpp: In function ‘int f(int)’:
fonction2.cpp:3:9: warning: suggest parentheses around assignment used as truth value |
Ce que l'on peut traduire par : « Je vous suggère de mettre des parenthèses autour de l'assignation si vous voulez l'utiliser comme test ». Le compilateur est poli, il suppose que mettre un seul symbole
= était ce que vous vouliez faire. Il vous propose donc de mettre des parenthèses autour pour bien montrer que c'est intentionnel.
À part ces deux exemples classiques d'erreurs, l'option
-Wall va aussi indiquer les parenthèses ambiguës, les
switch où des
case manquent, les déclarations de variables et fonctions inutilisées dans le reste du code et bien d'autres choses encore.
Malgré ce que son nom laisse suggérer, -Wall n'active pas tous les warnings possibles mais seulement les plus courants.
L'autre option de base est
-Wextra. Cette super-option active elle aussi une série de tests de conformité du code en particulier, elle autorise le compilateur à indiquer les variables initialisées ainsi que les arguments de fonctions inutilisés, par exemple :
Code : C++ - fonction3.cpp | int f(int a, int b)
{
int c;
if(c>a)
return 2;
else
return 3;
}
|
Cette fonction engendre deux messages d'avertissement :
Code : Console | fonction3.cpp:1:5: warning: unused parameter ‘b’
fonction3.cpp: In function ‘int f(int, int)’:
fonction3.cpp:4:3: warning: ‘c’ is used uninitialized in this function |
Cette fois, les messages sont très explicites : la variable
b n'est pas utilisée dans la fonction, ce qui est certainement une erreur et
c n'a pas de valeur lors du test, ce qui est à coup sûr une erreur.

Même si le code est valide et compile. J'espère que ça va vous convaincre d'utiliser au maximum les
warnings du compilateur.
Je vous conseille de toujours compiler avec les options -Wall et -Wextra : elles permettent d'éliminer les erreurs les plus courantes.
Il reste une dernière super-option à voir :
-pedantic. Elle vérifie que le code est conforme en tout point à la norme. Avec cette option activée et aucun message d'avertissement affiché, votre code devrait pouvoir compiler sur un autre OS et avec un autre compilateur. Mais ce n'est pas toujours aussi simple. Sachez simplement que cette option existe pour le jour où vous devrez créer du code portable.
Plus d'options
Après les options de base, je vous propose une petite sélection d'avertissements bien pratiques.
Les problèmes de pointeurs
Quand on manipule des pointeurs, il se peut que certaines opérations soient dangereuses ou aient des effets inattendus. Pour nous aider à repérer ces choses, il y a trois options à activer :
- -Wpointer-arith qui affiche des messages si l'on fait des calculs du type pointeur + nombre ;
- -Wcast-qual qui affiche des messages si l'on convertit un pointeur sur une constante en un pointeur sur une variable non constante ;
- -Wcast-align qui affiche des messages si l'on convertit des pointeurs d'un type à l'autre alors que leur taille en mémoire est différente (par exemple de char* vers int*).
Mais comme manipuler directement des pointeurs est une opération assez rare en C++, on n'a pas souvent besoin de ces options.
Les conversions
Le compilateur est autorisé à convertir des nombres d'un type à l'autre, par exemple de
double vers
int et vice-versa. Cela peut avoir des conséquences sur la précision des calculs et il est possible de demander au compilateur de nous avertir quand il fait ce genre de conversions.
- -Wconversion avertit quand des conversions automatiques sont effectuées.
- -Wdouble-promotion avertit quand un float est converti en double.
- -Wold-style-cast avertit quand des conversions « à la C » sont utilisées. En C++, on devrait toujours utiliser des static_cast ou les autres membres de la famille des casts.
Finalement, voyons quelques inclassables.
Les inclassables
Dans cette liste, il y a un peu de tout mais, comme toujours, il y a des cas particuliers qui pourront être évités grâce à ces options.
- -Wfloat-equal avertit si l'on teste l'égalité de deux nombres à virgule. Une erreur courante lorsque l'on fait du calcul scientifique.
- -Woverloaded-virtual affiche un message si une fonction virtuelle n'a pas la même signature dans une classe fille que dans sa classe mère.
- -Wshadow affiche un message s'il y a deux variables de même nom dans la même portion de code.
- -Weffc++ affiche un message si l'on ne suit pas les conseils de Scott Meyers présentés dans son livre Effective C++.
La liste est encore longue. Pour plus de détails, je vous renvoie à la
documentation de GCC où vous pourrez trouver une centaine d'autres options plus ou moins intéressantes pour augmenter le niveau d'avertissement de votre compilateur.
Personnellement, j'utilise toujours beaucoup de
warnings pour mes programmes afin de minimiser les erreurs de programmation. Voici ma liste d'options :
Code : Console | -pedantic -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -Wfloat-equal
-Wwrite-strings -Wpointer-arith -Wcast-qual -Wcast-align -Wconversion
-Wshadow -Weffc++ -Wredundant-decls -Wdouble-promotion -Winit-self -Wswitch-default
-Wswitch-enum -Wundef -Wlogical-op -Winline |
Cela fait beaucoup, mais c'est pour la bonne cause.
Pour les masochistes
Finalement, sachez qu'il est possible de convertir les messages d'avertissement en messages d'erreur. Votre code ne pourra alors compiler que si vous n'avez aucun
warning. Pour ce faire, il faut activer l'option
-Werror.
Et si vraiment vous êtes paranoïaques, vous pouvez demander à GCC de s'arrêter à la première erreur plutôt que d'essayer de continuer un peu plus loin et d'afficher toutes les erreurs rencontrées. Dans ce cas, il faut utiliser l'option
-Wfatal-errors.
Voyons maintenant une deuxième catégorie d'options de compilation : les optimisations.