344 votes

Pourquoi dois-je toujours activer les avertissements du compilateur ?

J'entends souvent dire que lorsque je compile des programmes C et C++, je dois "toujours activer les avertissements du compilateur". Pourquoi cela est-il nécessaire ? Comment dois-je m'y prendre ?

Parfois, j'entends aussi dire que je devrais "traiter les avertissements comme des erreurs". Devrais-je le faire ? Comment dois-je m'y prendre ?

376voto

n.m. Points 30344

Pourquoi activer les avertissements ?

Les compilateurs C et C++ sont réputés pour ne pas signaler certaines erreurs courantes des programmeurs. par défaut comme :

  • oublier d'initialiser une variable
  • en oubliant de return une valeur issue d'une fonction
  • arguments dans printf y scanf familles ne correspondant pas à la chaîne de format
  • une fonction est utilisée sans être déclarée au préalable (C uniquement)

Ceux-ci peuvent être détectés et signalés, mais généralement pas par défaut ; cette fonctionnalité doit être demandée explicitement via les options du compilateur.

Comment activer les avertissements ?

Cela dépend de votre compilateur.

Les compilateurs C et C++ de Microsoft comprennent des commutateurs tels que /W1 , /W2 , /W3 , /W4 y /Wall . Utilisez au moins /W3 . /W4 y /Wall peut émettre de faux avertissements pour les fichiers d'en-tête du système, mais si votre projet compile proprement avec l'une de ces options, allez-y. Ces options sont mutuellement exclusives.

La plupart des autres compilateurs comprennent des options comme -Wall , -Wpedantic y -Wextra . -Wall est essentiel et tous les autres sont recommandés (notez que, malgré son nom, -Wall n'active que les avertissements les plus importants, et non todo d'entre eux). Ces options peuvent être utilisées séparément ou toutes ensemble.

Votre IDE peut avoir un moyen de les activer à partir de l'interface utilisateur.

Pourquoi traiter les avertissements comme des erreurs ? Ce ne sont que des avertissements !

Un avertissement du compilateur signale un problème potentiellement grave dans votre code. Les problèmes énumérés ci-dessus sont presque toujours fatals ; les autres peuvent l'être ou non, mais vous voulez que la compilation échoue même si il s'avère que c'est une fausse alerte. Examinez chaque alerte, trouvez la cause profonde et réparez-la. Dans le cas d'une fausse alerte, contournez-la, c'est-à-dire utilisez une fonctionnalité ou une construction linguistique différente afin que l'alerte ne soit plus déclenchée. Si cela s'avère très difficile, désactivez cet avertissement particulier au cas par cas.

Vous ne voulez pas laisser les avertissements comme tels, même s'ils sont tous de fausses alertes. Cela pourrait être correct pour de très petits projets où le nombre total d'avertissements émis est inférieur à 7. Au-delà, il est facile pour un nouvel avertissement de se perdre dans un flot d'anciens avertissements familiers. Ne permettez pas cela. Faites en sorte que tous vos projets compilent proprement.

Notez que cela s'applique au développement de programmes. Si vous diffusez votre projet au monde entier sous la forme de la source, il peut être judicieux de ne pas fournir -Werror ou l'équivalent dans votre libéré build script. Les gens pourraient essayer de construire votre projet avec une version différente du compilateur, ou avec un compilateur différent tout court, qui pourrait avoir un ensemble différent d'avertissements activés. Vous pouvez vouloir que leur construction réussisse. C'est toujours une bonne idée de garder les avertissements activés, afin que les personnes qui voient des messages d'avertissement puissent vous envoyer des rapports de bogue ou des correctifs.

Comment traiter les avertissements comme des erreurs ?

Cela se fait à nouveau à l'aide de commutateurs de compilateur. /WX est pour Microsoft, la plupart des autres utilisent -Werror . Dans les deux cas, la compilation échouera si des avertissements sont produits.

118 votes

J'ai posté cette question-réponse parce que j'en ai assez de dire aux gens d'activer les avertissements. Maintenant, je peux simplement les diriger ici (ou, si je suis d'humeur particulièrement mauvaise, fermer leur question en tant que dupe). Vous êtes invités à améliorer cette réponse ou à ajouter la vôtre !

17 votes

Vous pouvez également utiliser clang's -Tout

0 votes

Les avertissements (et les erreurs) sont également "perdus" en raison de la limitation du nombre de messages notifiés ou parce que le compilateur ignore les doublons d'un même avertissement.

102voto

Steve Summit Points 16971

Le C est, comme chacun sait, un langage de très bas niveau en ce qui concerne les HLL. Le C++, bien qu'il puisse sembler être un langage de niveau considérablement plus élevé que le C, partage encore un certain nombre de ses caractéristiques. Et l'une de ces caractéristiques est que les langages ont été conçus par des programmeurs, pour des programmeurs -- et, plus précisément, des programmeurs qui savaient ce qu'ils faisaient.

(Pour le reste de cette réponse, je vais me concentrer sur le C. La plupart de ce que je vais dire s'applique également au C++, mais peut-être pas aussi fortement. Bien que, comme l'a dit Bjarne Stroustrup, "Le C permet de se tirer facilement une balle dans le pied ; le C++ rend les choses plus difficiles, mais quand on y arrive, ça fait sauter toute la jambe." ]

Si tu sais ce que tu fais vraiment savoir ce que vous faites - il faut parfois "enfreindre les règles". Mais la plupart du temps, nous sommes d'accord pour dire que des règles bien intentionnées nous évitent à tous des ennuis, et qu'enfreindre délibérément ces règles en permanence est une mauvaise idée.

Mais en C et C++, il y a un nombre étonnamment élevé de choses que vous pouvez faire qui sont des "mauvaises idées" mais qui ne sont pas formellement "contre les règles". Parfois, il s'agit d'une mauvaise idée à certains moments (mais qui peut être défendable à d'autres moments) ; parfois, il s'agit d'une mauvaise idée pratiquement tout le temps. Mais la tradition a toujours été la suivante no pour avertir de ces choses - parce que, encore une fois, l'hypothèse est que les programmeurs savent ce qu'ils font, ils ne feraient pas ces choses sans une bonne raison, ils seraient ennuyés par un tas d'avertissements inutiles.

Mais bien sûr, tous les programmeurs ne vraiment savent ce qu'ils font. Et, en particulier, chaque programmeur C (quelle que soit son expérience) passe par une phase de programmeur C débutant. Et même les programmeurs C expérimentés peuvent être négligents et faire des erreurs.

Enfin, l'expérience a montré non seulement que les programmeurs font des erreurs, mais que ces erreurs peuvent avoir des conséquences réelles et graves. Si vous faites une erreur, que le compilateur ne vous en avertit pas et que, pour une raison ou pour une autre, le programme ne plante pas immédiatement ou ne fait pas quelque chose de manifestement mauvais à cause de cette erreur, celle-ci peut rester cachée, parfois pendant des années, jusqu'à ce qu'elle provoque une catastrophe. vraiment gros problème.

Il s'avère donc que, la plupart du temps, les avertissements sont une bonne idée, après tout. Même les programmeurs expérimentés ont appris (en fait, c'est " notamment les programmeurs expérimentés ont appris") que, dans l'ensemble, les avertissements ont tendance à faire plus de bien que de mal. Pour chaque fois que vous avez fait quelque chose de mal délibérément et que l'avertissement a été une nuisance, il y a probablement au moins dix fois où vous avez fait quelque chose de mal par accident et où l'avertissement vous a évité des problèmes supplémentaires. Et la plupart des avertissements peuvent être désactivés ou contournés pour les quelques fois où vous voulez vraiment faire la "mauvaise" chose.

(Un exemple classique d'une telle "erreur" est le test if(a = b) . La plupart du temps, il s'agit d'une erreur, et la plupart des compilateurs actuels en tiennent compte, certains même par défaut. Mais si vous vraiment voulait à la fois attribuer b a a et tester le résultat, vous pouvez désactiver l'avertissement en tapant if((a = b)) .)

La deuxième question est la suivante : pourquoi voulez-vous demander au compilateur de traiter les avertissements comme des erreurs ? Je dirais que c'est à cause de la nature humaine, plus précisément, la réaction trop facile de dire "Oh, c'est juste un avertissement, ce n'est pas si important, je nettoierai ça plus tard". Mais si vous êtes un procrastinateur (et je ne sais pas pour vous, mais moi je suis une terrible ), il est facile de repousser le nettoyage pour toujours, et si vous prenez l'habitude d'ignorer les avertissements, il devient de plus en plus facile de manquer un nettoyage. important un message d'avertissement qui reste là, inaperçu, au milieu de tous ceux que vous ignorez.

Demander au compilateur de traiter les avertissements comme des erreurs est donc une petite astuce que vous pouvez utiliser pour contourner cette faiblesse humaine.

Personnellement, je n'insiste pas autant pour traiter les avertissements comme des erreurs. (En fait, si je suis honnête, je peux dire que je n'active pratiquement jamais cette option dans ma programmation "personnelle"). Mais vous pouvez être sûr que j'ai activé cette option au travail, où notre guide de style (que j'ai écrit) rend son utilisation obligatoire. Et je dirais - je pense que la plupart des programmeurs professionnels diraient - que tout magasin qui ne traite pas les avertissements comme des erreurs en C se comporte de manière irresponsable, n'adhère pas aux meilleures pratiques de l'industrie communément acceptées.

9 votes

"des programmeurs qui savaient ce qu'ils faisaient" - LOL ; c'est le sophisme du "no true Scotsman" si j'en ai jamais vu un :)

3 votes

@Dancrumb LOL en retour à vous. Je ne suis jamais tout à fait sûr de comprendre le Pas de vrai écossais fallacieux, mais j'aime ça, donc ce sera un bon exercice pour moi. Je suppose que l'application ici est comme ceci : "Aucun programmeur C n'écrirait jamais if(a = b) donc nous n'avons pas besoin de l'avertir." (Puis quelqu'un produit une liste de 10 bogues critiques dans 10 produits publiés qui résultent de cette erreur particulière). "Ok, non expérimenté Un programmeur C n'écrirait jamais ça..."

3 votes

@SteveSummit mais un realmente Un programmeur C expérimenté peut écrire if (returnCodeFromFoo = foo(bar)) et le signifier, pour capturer et tester le code en un seul endroit. (Supposons que la uniquement l'objectif de foo est d'avoir des effets secondaires !) Le fait qu'un vraiment vraiment Un programmeur expérimenté peut savoir que ce n'est pas un bon style de codage, mais ce n'est pas la question ;)

41voto

Cort Ammon Points 1584

Les avertissements sont les meilleurs conseils que certains des développeurs C++ les plus compétents ont pu intégrer dans une application. Ils valent la peine d'être conservés.

Le C++, étant un langage complet de Turing, présente de nombreux cas où le compilateur doit simplement croire que vous savez ce que vous faites. Cependant, il existe de nombreux cas où le compilateur peut se rendre compte que vous n'aviez probablement pas l'intention d'écrire ce que vous avez écrit. Un exemple classique est celui des codes printf() qui ne correspondent pas aux arguments, ou des chaînes std::passées à printf (non pas que cela jamais m'arrive à moi !). Dans ces cas, le code que vous avez écrit n'est pas une erreur. C'est une expression C++ valide avec une interprétation valide sur laquelle le compilateur doit agir. Mais le compilateur a la forte intuition que vous avez simplement négligé quelque chose qui est facile à détecter pour un compilateur moderne. Ce sont des avertissements. Ce sont des choses qui sont évidentes pour un compilateur, utilisant toutes les règles strictes du C++ à sa disposition, et que vous pourriez avoir négligées.

Désactiver les avertissements ou les ignorer, c'est comme choisir d'ignorer les conseils gratuits de personnes plus compétentes que vous. C'est une leçon d'huberis qui se termine soit lorsque vous volez trop près du soleil et que vos ailes fondent, soit lorsqu'une erreur de corruption de mémoire se produit. Entre les deux, je préfère tomber du ciel n'importe quand !

"Traiter les avertissements comme des erreurs" est la version extrême de cette philosophie. L'idée ici est que vous résolvez chaque l'avertissement que le compilateur vous donne - vous écoutez chaque petit conseil gratuit et vous agissez en conséquence. Que ce soit un bon modèle de développement pour vous dépend de l'équipe et du type de produit sur lequel vous travaillez. C'est l'approche ascétique qu'un moine pourrait avoir. Pour certains, cela fonctionne très bien. Pour d'autres, ce n'est pas le cas.

Sur bon nombre de mes applications, nous ne traitons pas les avertissements comme des erreurs. Nous le faisons parce que ces applications particulières doivent être compilées sur plusieurs plates-formes avec plusieurs compilateurs d'âges différents. Parfois, nous constatons qu'il est impossible de corriger un avertissement sur un côté sans qu'il se transforme en avertissement sur une autre plate-forme. Nous sommes donc simplement prudents. Nous respectons les avertissements, mais nous ne nous plions pas en quatre pour eux.

13 votes

Qu'est-ce que le fait que le C++ soit complet au sens de Turing a à voir avec ça ? Beaucoup de langages sont complets et ne vous font pas confiance si vous faites quelque chose de mal. ....

4 votes

@KamiKaze chaque langue aura des erreurs idiomatiques (par exemple, Java ne peut pas vous empêcher d'écrire une erreur inconsistante. equals / hashCode ), et c'est une question de qualité de mise en œuvre que de savoir lesquels de ces éléments sont rapportés.

2 votes

@KamiKaze Le bit de complétude de Turing intervient pour montrer qu'il existe des cas où le compilateur ne peut pas prouver que votre code ne fonctionnera pas comme prévu. Ceci est important car les compilateurs ne peuvent pas faire de tout code "incorrect" une erreur. Les erreurs ne peuvent être réservées qu'aux comportements dont les concepteurs du langage sont certains qu'ils seront toujours "mauvais". (généralement parce qu'ils conduisent à des chemins incohérents).

21voto

RedSonja Points 143

Non seulement la gestion des avertissements permet d'obtenir un meilleur code, mais elle fait de vous un meilleur programmeur. Les avertissements vous signalent des choses qui peuvent vous sembler insignifiantes aujourd'hui, mais un jour cette mauvaise habitude reviendra et vous arrachera la tête.

Utilisez le bon type, renvoyez cette valeur, évaluez cette valeur de retour. Prenez le temps de réfléchir : "Est-ce vraiment le bon type dans ce contexte ?" "Ai-je besoin de retourner cette valeur ?" Et le plus important : "Ce code va-t-il être portable pendant les 10 prochaines années ?".

Prenez l'habitude d'écrire du code sans avertissement dès le départ.

19voto

gsamaras Points 9567

Les avertissements non fixes tôt ou tard, conduire à des erreurs dans votre code .


Le débogage d'un défaut de segmentation, par exemple, exige du programmeur qu'il retrace la racine (cause) du défaut, qui se trouve généralement à un endroit du code antérieur à la ligne qui a finalement causé le défaut de segmentation.

Il est très typique que la cause soit une ligne pour laquelle le compilateur avait émis un avertissement que vous avez ignoré, et que la ligne qui a causé la faute de segmentation soit la ligne qui a finalement généré l'erreur.

Réparer l'avertissement conduit à réparer le problème Un classique !

Une démonstration de ce qui précède.. Considérons le code suivant :

#include <stdio.h>

int main(void) {
  char* str = "Hello world!";
  int idx;

  // Colossal amount of code here, irrelevant to 'idx'

  printf("%c\n", str[idx]);

  return 0;
}

qui, lorsqu'il est compilé avec le flag "Wextra" passé à GCC, donne :

main.c: In function 'main':
main.c:9:21: warning: 'idx' is used uninitialized in this function [-Wuninitialized]
    9 |   printf("%c\n", str[idx]);
      |                     ^

que je pourrait ignorer et exécuter le code de toute façon.. Et j'assisterais alors à un "grand" défaut de segmentation, comme disait mon professeur d'épicurisme IP :

Défaut de segmentation

Pour déboguer ce problème dans un scénario réel, il faudrait partir de la ligne qui provoque le défaut de segmentation et tenter de retrouver la Racine de la cause Il faudrait chercher ce qui est arrivé à i y str dans cette quantité colossale de code là-bas...

Jusqu'à ce qu'un jour, ils se retrouvent dans la situation où ils découvrent que idx est utilisé sans être initialisé, il a donc une valeur résiduelle, ce qui a pour conséquence d'indexer la chaîne (bien) au-delà de ses limites, ce qui conduit à une erreur de segmentation.

Si seulement ils n'avaient pas ignoré l'avertissement, ils auraient trouvé le bug immédiatement !

5 votes

Pour répondre à votre titre : pas nécessairement. Par exemple, un avertissement suggérant d'utiliser des parenthèses dans une formule qui n'en a pas vraiment besoin renvoie à un non-problème qui ne provoquera jamais d'erreur. Les précédences des opérateurs dans un langage de programmation donné ne changent pas. Jamais.

4 votes

@MarcvanLeeuwen L'exemple que vous citez puede se transforment en erreur tho, par exemple si le programmeur qui ne se souvient pas de la précédence des opérateurs modifie un peu la formule. L'avertissement vous dit : "cela pourrait ne pas être clair pour quelqu'un à un moment donné, ajoutez quelques parenthèses pour le rendre plus clair". Bien que l'on doive convenir que le titre du post original n'est pas toujours vrai.

0 votes

^ Tout peut être transformé en erreur. Il est tout aussi facile d'introduire un bogue dans un code partiellement parenthésé que dans un code entièrement parenthésé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X