Pourquoi devrais-je toujours activer les avertissements du compilateur?


302

J'entends souvent que lors de la compilation de programmes C et C ++, je dois "toujours activer les avertissements du compilateur". Pourquoi est-ce nécessaire? Comment je fais ça?

Parfois, j'entends aussi que je dois "traiter les avertissements comme des erreurs". Devrais-je? Comment je fais ça?

Réponses:


341

Pourquoi activer les avertissements?

Les compilateurs C et C ++ sont notoirement mauvais pour signaler certaines erreurs de programmation courantes par défaut , telles que:

  • oublier d'initialiser une variable
  • oublier à returnune valeur d'une fonction
  • arguments printfet scanffamilles 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 explicitement demandée via les options du compilateur.

Comment activer les avertissements?

Cela dépend de votre compilateur.

Microsoft C et compilateurs C comprennent des commutateurs aiment /W1, /W2, /W3, /W4et /Wall. Utilisez au moins /W3. /W4et /Wallpeut émettre de faux avertissements pour les fichiers d'en-tête du système, mais si votre projet se compile proprement avec l'une de ces options, allez-y. Ces options s'excluent mutuellement.

La plupart des autres compilateurs comprennent des options telles que -Wall, -Wpedanticet -Wextra. -Wallest essentiel et tout le reste est recommandé (notez que, malgré son nom, -Wallne permet que les avertissements les plus importants, pas tous ). 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; d'autres peuvent l'être ou non, mais vous voulez que la compilation échoue même si elle s'avère être une fausse alarme. Analysez chaque avertissement, trouvez la cause première et corrigez-le. Dans le cas d'une fausse alarme, contournez-la, c'est-à-dire utilisez une fonction ou une construction de langage différente pour que l'avertissement ne soit plus déclenché. Si cela s'avère très difficile, désactivez cet avertissement particulier au cas par cas.

Vous ne voulez pas simplement laisser des avertissements comme avertissements, même s'ils sont tous de fausses alarmes. Cela pourrait être OK pour de très petits projets où le nombre total d'avertissements émis est inférieur à 7. Rien de plus, et il est facile pour un nouvel avertissement de se perdre dans un flot d'anciens familiers. Ne permettez pas ça. Faites simplement compiler proprement tout votre projet.

Notez que cela s'applique au développement du programme. Si vous publiez votre projet dans le monde sous la forme source, il peut être judicieux de ne pas fournir -Werrorou équivalent dans votre script de build publié . Les gens peuvent essayer de créer votre projet avec une version différente du compilateur, ou avec un compilateur tout à fait différent, qui peut avoir un ensemble d'avertissements différent activé. Vous voudrez peut-être que leur version 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 bogues ou des correctifs.

Comment traiter les avertissements comme des erreurs?

Cela se fait à nouveau avec les commutateurs du compilateur. /WXest pour Microsoft, la plupart des autres utilisent -Werror. Dans les deux cas, la compilation échouera si des avertissements sont générés.


107
J'ai publié ce Q & A parce que je suis fatigué de dire aux gens d'activer les avertissements. Maintenant, je peux simplement les pointer ici (ou, si je suis d'humeur particulièrement mauvaise, fermer leur question en dupe). Vous êtes invités à améliorer cette réponse ou à ajouter la vôtre!
n. «pronoms» m.

16
Vous pouvez également utiliser -Weverything
pmg le

9
Le seul modificateur que j'ajouterais est que certains avertissements peuvent ne pas être utiles pour votre application. (J'ai vu des avertissements selon lesquels le compilateur a ajouté 2 octets de remplissage entre les éléments d'une structure. L'application était destinée au prototypage, donc un peu de mémoire gaspillée ne nous a pas dérangés.) Traitez tous les avertissements comme des erreurs et ne désactivez un avertissement que si vous savez pourquoi cet avertissement ne vous aidera pas.
Kyle A

20
L'inconvénient de traiter les avertissements comme des erreurs pour les personnes qui suivent vos instructions de génération par défaut est que votre code pourrit en tant que compilateurs ajoutent de nouveaux avertissements. Les utilisateurs qui téléchargent votre code et tentent de le construire à l'avenir peuvent ne pas pouvoir le faire, car leur compilateur est trop nouveau et émet un avertissement concernant des parenthèses supplémentaires ou quelque chose que votre compilateur ne se soucie pas. L'utilisateur qui rencontre l'erreur n'est pas responsable de votre code ou de votre système de génération et n'a aucune idée de comment désactiver le traitement des avertissements comme des erreurs et réellement créer votre projet.
interfect

15
@interfect Oui, cela m'est arrivé plusieurs fois. Pas de biggie. Si vous avez choisi de créer un logiciel non entretenu à l' aide d'un compilateur avec lequel il n'a jamais été testé, eh bien, vous feriez mieux d'être prêt à effectuer vous-même une maintenance.
n. «pronoms» m.

94

C est, comme on le sait, un langage de bas niveau comme les HLL. C ++, bien qu'il puisse sembler être un langage de niveau considérablement plus élevé que C, partage toujours un certain nombre de ses traits. Et l'un de ces traits est que les langages ont été conçus par des programmeurs, pour des programmeurs - et, spécifiquement, des programmeurs qui savaient ce qu'ils faisaient.

[Pour le reste de cette réponse, je vais me concentrer sur C. La plupart de ce que je vais dire s'applique également au C ++, mais peut-être pas aussi fortement. Bien que Bjarne Stroustrup l'ait célèbre, "C facilite la prise de vue dans le pied; C ++ rend la tâche plus difficile, mais lorsque vous le faites, vous vous enlevez toute la jambe." ]

Si vous savez ce que vous faites - savez vraiment ce que vous faites - parfois, vous devrez peut-être «enfreindre les règles». Mais la plupart du temps, la plupart d'entre nous seront d'accord pour dire que des règles bien intentionnées nous empêchent tous d'avoir des ennuis, et que de les enfreindre à tout moment sans motif est une mauvaise idée.

Mais en C et C ++, il y a un nombre étonnamment grand de choses que vous pouvez faire qui sont de "mauvaises idées" mais qui ne sont pas formellement "contraires aux règles". Parfois, c'est une mauvaise idée parfois (mais peut être défendable d'autres fois); parfois c'est une mauvaise idée presque tout le temps. Mais la tradition a toujours été de ne pas 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 savent pas vraiment ce qu'ils font. Et, en particulier, chaque programmeur C (peu importe son expérience) passe par une phase d'être un 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 et que le compilateur ne vous en avertit pas et que le programme ne se bloque pas immédiatement ou ne fait pas quelque chose de mal à cause de cela, l'erreur peut se cacher là, cachée, parfois pendant des années, jusqu'à ce qu'elle provoque un très 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 " surtout 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 était une nuisance, il y a probablement au moins dix fois que vous avez fait quelque chose de mal par accident et l'avertissement vous a évité d'autres ennuis. Et la plupart des avertissements peuvent être désactivés ou contournés ces quelques fois où vous voulez vraiment faire la "mauvaise" chose.

(Un exemple classique d'une telle « erreur » est le test La if(a = b)plupart du temps, cela est une erreur, donc la plupart des compilateurs ces jours -ci mettent en garde à ce sujet -.. Certains même par défaut , mais si vous vraiment vouliez assignent bà aet tester le résultat, vous pouvez désactiver l'avertissement en tapant if((a = b)).)

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

Donc, demander au compilateur de traiter les avertissements comme des erreurs est une petite astuce que vous pouvez jouer sur vous-même pour contourner cette cible humaine.

Personnellement, je n'insiste pas autant pour traiter les avertissements que les 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 cette option est activée au travail, où notre guide de style (que je écrit) rend obligatoire son utilisation. Et je dirais - je pense que la plupart des programmeurs professionnels diraient - que tout magasin qui ne traite pas les avertissements comme des erreurs dans C se comporte de manière irresponsable, n'adhère pas aux meilleures pratiques de l'industrie communément acceptées.


9
"des programmeurs qui savaient ce qu'ils faisaient" - LOL; il y a un sophisme "pas de véritable écossais" si j'en ai vu un :)
Dancrumb

3
@Dancrumb LOL retour atcha. Je ne suis jamais tout à fait sûr de comprendre l' erreur de No true Scotsman , 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." (Ensuite, quelqu'un produit une liste de 10 bogues critiques dans 10 produits publiés qui résultent de cette erreur particulière.) "D'accord, aucun programmeur C expérimenté n'écrirait jamais cela ..."
Steve Summit

3
@SteveSummit mais un programmeur C vraiment expérimenté peut l'écrire if (returnCodeFromFoo = foo(bar))et le signifier, pour capturer et tester le code en un seul endroit (supposons que le seul but de foosoit d'avoir des effets secondaires!) Le fait qu'un programmeur vraiment vraiment expérimenté sache que ce n'est pas un un bon style de codage est à côté du point;)
alephzero

5
Le fait est que la plupart des programmeurs très expérimentés activent la plupart des avertissements, sinon tous. S'ils veulent utiliser quelque chose comme ça if (returnCodeFromFoo = foo(bar)), alors ils mettent un commentaire et désactivent l'avertissement (de sorte que lorsque le programmeur de maintenance l'examine 4 ans plus tard, il / elle se rendra compte que le code est intentionnel. Cela dit, j'ai travaillé avec quelqu'un qui (dans Microsoft C ++ land) a insisté sur le fait que combiner / Wall avec traiter les avertissements comme des erreurs était la voie à suivre. Ce n'est pas le cas (à moins que vous ne vouliez
ajouter

3
En tant que personne qui n'écrit pas de code sur une base quotidienne, mais quand je le fais, cela a tendance à être nu (souvent sur une carte de ma propre conception), je trouve les avertissements inestimables. Lorsque vous placez des valeurs dans des registres internes (pour un emplacement de descripteur DMA, par exemple), l'avertissement concernant la conversion en pointeur signifie que je fais un cast pour effacer l'avertissement. Ce ne serait pas une erreur, mais si quelqu'un d'autre (ou même moi-même!) Récupère ce code dans quelques mois, cela pourrait être déroutant. En outre, j'applique également la règle d'absence d'avertissement aux sorties de mes outils de CAO.
Peter Smith

39

Les avertissements sont les meilleurs conseils que certains des développeurs C ++ les plus qualifiés pourraient intégrer dans une application. Ils valent la peine de rester.

C ++, étant un langage complet de Turing, a de nombreux cas où le compilateur doit simplement avoir confiance que vous saviez ce que vous faites. Cependant, il existe de nombreux cas où le compilateur peut réaliser que vous n'aviez probablement pas l'intention d'écrire ce que vous avez écrit. Un exemple classique est les codes printf () qui ne correspondent pas aux arguments, ou les chaînes std :: passées à printf (pas que cela m'arrive jamais !). Dans ces cas, le code que vous avez écrit n'est pas une erreur. Il s'agit d'une expression C ++ valide avec une interprétation valide sur laquelle le compilateur peut agir. Mais le compilateur a une forte intuition que vous avez simplement ignoré 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, que vous auriez pu ignorer.

Désactiver ou ignorer les avertissements, 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 qu'une erreur de corruption de mémoire se produit. Entre les deux, je prendrai la chute du ciel tous les jours!

"Traiter les avertissements comme des erreurs" est la version extrême de cette philosophie. L'idée ici est que vous résolvez chaque avertissement que le compilateur vous donne - vous écoutez chaque petit conseil gratuit et 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 en fait impossible de fixer un avertissement d'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 arrière pour eux.


11
Qu'est-ce que C ++ étant Turing complet a à voir avec cela. Beaucoup de langues sont complètes et ne vous font pas confiance si vous faites quelque chose de mal ....
Au revoir SE

3
@KamiKaze chaque langue aura des erreurs idiomatiques (par exemple Java ne peut pas vous empêcher d'écrire un equals/ hashCode) incohérent , et c'est un problème de qualité d'implémentation qui est signalé.
Caleth

2
@KamiKaze Le bit d'exhaustivité de Turing arrive pour montrer qu'il y a 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 de langage sont certains qu'ils seront toujours "erronés". (généralement parce qu'il conduit sur des chemins incohérents).
Cort Ammon

2
Ce qui souligne également le défi avec «tous les avertissements sont des erreurs». Les avertissements sont, par conception, plus opportunistes, se déclenchant sur un code potentiellement correct en échange d'un déclenchement sur un code incorrect plus souvent. Les avertissements en tant qu'erreurs vous empêchent d'exercer toutes les capacités de la langue.
Cort Ammon

2
Cependant, en général, les programmeurs veulent un langage qui fait plus qu'une chose "sûre". Nous voulons un langage qui fasse ce que nous pensions lui avoir dit de faire. Ainsi, les avertissements restent importants parce que la classe réelle de choses que nous voulons que l'ordinateur fasse est une classe sémantique. Le compilateur peut y remédier en définissant «incorrect» ou «dangereux», mais à la fin, vous avez toujours une superclasse des comportements que le programmeur voulait que le programme fasse. Les avertissements aident à réduire cette superclasse.
Cort Ammon

19

Non seulement la gestion des avertissements améliore le code, mais elle fait de vous un meilleur programmeur. Des avertissements vous renseigneront sur des choses qui peuvent vous sembler peu aujourd'hui, mais un jour, cette mauvaise habitude reviendra et vous mordra la tête.

Utilisez le type correct, renvoyez cette valeur, évaluez cette valeur de retour. Prenez le temps et réfléchissez "Est-ce vraiment le bon type dans ce contexte?" "Dois-je retourner ça?" Et le biggie; "Ce code va-t-il être portable pour les 10 prochaines années?"

Prenez l'habitude d'écrire du code sans avertissement en premier lieu.


17

Les autres réponses sont excellentes et je ne veux pas répéter ce qu'elles ont dit.

Un autre aspect de «pourquoi activer les avertissements» qui n'a pas été correctement abordé est qu'ils aident énormément à la maintenance du code. Lorsque vous écrivez un programme de taille importante, il devient impossible de garder le tout dans votre tête à la fois. Vous avez généralement une ou trois fonctions que vous écrivez et pensez activement, et peut-être un ou trois fichiers sur votre écran auxquels vous pouvez vous référer, mais la majeure partie du programme existe quelque part en arrière-plan et vous devez avoir confiance qu'il continue de travailler.

Avoir des avertissements et les avoir aussi énergiques et en face que possible, vous aide à vous alerter si quelque chose que vous changez crée des problèmes pour quelque chose que vous ne pouvez pas voir.

Prenons par exemple l'avertissement de bruit -Wswitch-enum. Cela déclenche un avertissement si vous utilisez un commutateur sur une énumération et manquez l'une des valeurs d'énumération possibles. C'est quelque chose que vous pourriez penser serait une erreur improbable: vous avez probablement au moins regardé la liste des valeurs d'énumération lorsque vous avez écrit l'instruction switch. Vous pourriez même avoir un IDE qui a généré les options de commutation pour vous, ne laissant aucune place à l'erreur humaine.

Cet avertissement prend tout son sens lorsque, six mois plus tard, vous ajoutez une autre entrée possible à l'énumération. Encore une fois, si vous pensez au code en question, tout ira probablement bien. Mais si cette énumération est utilisée à plusieurs fins différentes et que c'est pour l'une de celles que vous avez besoin de l'option supplémentaire, il est très facile d'oublier de mettre à jour un commutateur dans un fichier que vous n'avez pas touché depuis 6 mois.

Vous pouvez penser aux avertissements de la même manière que vous le pensez aux cas de tests automatisés: ils vous aident à vous assurer que le code est sensé et à faire ce dont vous avez besoin lorsque vous l'écrivez pour la première fois, mais ils aident encore plus à vous assurer qu'il continue de faire ce dont vous avez besoin pendant que vous le produisez. La différence est que les cas de test fonctionnent très étroitement aux exigences de votre code et que vous devez les écrire, tandis que les avertissements fonctionnent largement selon des normes raisonnables pour presque tout le code, et ils sont très généreusement fournis par les boffins qui font les compilateurs.


9
L'autre façon dont ils aident à la maintenance est lorsque vous regardez le code de quelqu'un d'autre et ne pouvez pas dire si un effet secondaire était intentionnel. Avec des avertissements, vous savez qu'ils étaient au moins au courant du problème.
Robin Bennett

Ou dans mon cas, vous importez un fichier à partir d'un système intégré qui contient une instruction de changement de ligne 3000+ sur une énumération avec plusieurs milliers de valeurs. Les avertissements "échoués" (évités en utilisant goto) masquaient un certain nombre de bogues "non traités" ... le compilateur incorporé n'en émettait aucun, mais les bogues étaient néanmoins importants.
Móż

15

Des avertissements non fixes entraîneront tôt ou tard des erreurs dans votre code .


Le débogage d'une erreur de segmentation, par exemple, nécessite que le programmeur trace la racine (cause) de l'erreur, qui se trouve généralement à un endroit antérieur dans votre code que la ligne qui a finalement causé l'erreur 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 la ligne qui a provoqué la faute de segmentation la ligne qui a finalement jeté l'erreur.

La correction de l'avertissement conduit à la résolution du problème .. Un classique!

Une démonstration de ce qui précède. Considérez 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, une fois compilé avec le drapeau "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 pourrais ignorer et exécuter le code de toute façon .. Et puis je serais témoin d'un "grand" défaut de segmentation, comme disait mon professeur d'épicure IP:

Erreur de segmentation

Afin de déboguer cela dans un scénario du monde réel, on commencerait par la ligne qui provoque la faute de segmentation et tenter de tracer quelle est la racine de la cause. Ils devraient rechercher ce qui est arrivé à iet à l' strintérieur de ce montant colossal de code là-bas ...

Jusqu'à ce qu'un jour, ils se retrouvent dans la situation où ils découvrent qu'il idxest utilisé non initialisé, donc il a une valeur poubelle, ce qui entraîne l'indexation de 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 bogue immédiatement!


4
À votre titre: pas nécessairement. Par exemple, un avertissement suggérant d'utiliser des parenthèses dans une formule qui n'en a vraiment pas besoin pointe vers un non-problème qui ne provoquera jamais d'erreur. Les priorités des opérateurs dans un langage de programmation donné ne changent pas. Déjà.
Marc van Leeuwen

4
@MarcvanLeeuwen L'instance que vous citez peut se transformer en erreur, par exemple si le programmeur qui ne se souvient pas de la priorité de l'opérateur modifie un peu la formule. L'avertissement vous dit: "cela pourrait ne pas être clair pour quelqu'un à un moment donné, ajoutez des parenthèses pour le rendre plus clair". Bien qu'il faille convenir que le titre de l'article d'origine n'est pas toujours vrai.
Hubert Jasieniecki

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

... En passant, j'ai des questions pour le débogueur dont la première réaction à "Oh, il s'est séparé de str[idx]" n'est pas "D'accord, où sont stret idxdéfinis?"
Justin Time - Rétablir Monica

2
Vous avez de la chance si vous obtenez un défaut de segmentation. Si vous êtes moins chanceux, vous pourriez par hasard idxêtre la valeur que vous attendiez lors de votre test (pas trop improbable si la valeur attendue est 0), et en fait, pointer vers certaines données sensibles qui ne devraient jamais être imprimées lors du déploiement.
celtschk

14

Traiter les avertissements comme des erreurs n'est qu'un moyen d'autodiscipline: vous compiliez un programme pour tester cette nouvelle fonctionnalité brillante, mais vous ne pouvez pas le faire tant que vous n'avez pas corrigé les parties bâclées. Aucune information supplémentaire n'est Werrorfournie, elle définit simplement les priorités très clairement:

N'ajoutez pas de nouveau code avant d'avoir résolu les problèmes dans le code existant

C'est vraiment l'état d'esprit qui est important, pas les outils. La sortie de diagnostic du compilateur est un outil. MISRA (pour C embarqué) est un autre outil. Peu importe celui que vous utilisez, mais les avertissements du compilateur sont sans doute l'outil le plus simple que vous pouvez obtenir (c'est juste un indicateur à définir) et le rapport signal / bruit est très élevé. Il n'y a donc aucune raison de ne pas l'utiliser.

Aucun outil n'est infaillible. Si vous écrivez const float pi = 3.14;, la plupart des outils ne vous diront pas que vous avez défini π avec une mauvaise précision, ce qui peut entraîner des problèmes en cours de route. La plupart des outils ne lèveront pas les sourcils if(tmp < 42), même s'il est communément admis que donner des variables à des noms dénués de sens et utiliser des nombres magiques est un moyen de catastrophe dans les grands projets. Vous devez comprendre que tout code de "test rapide" que vous écrivez n'est que cela: un test, et vous devez le faire correctement avant de passer à d'autres tâches, pendant que vous voyez toujours ses défauts. Si vous laissez ces codes tels quels, le débogage si après avoir passé deux mois à ajouter de nouvelles fonctionnalités sera beaucoup plus difficile.

Une fois que vous êtes dans le bon état d'esprit, il est inutile de l'utiliser Werror. Le fait d'avoir des avertissements comme avertissements vous permettra de prendre une décision éclairée sur l'opportunité d'exécuter la session de débogage que vous étiez sur le point de démarrer ou de l'abandonner et de corriger les avertissements en premier.


3
Pour le meilleur ou pour le pire, l' clippyoutil de peluchage pour Rust avertira en fait de la constante "3.14". C'est en fait un exemple dans les documents . Mais comme vous pouvez le deviner d'après le nom, clippyest fier d'être très serviable.
emk

1
@emk Merci pour cet exemple, je devrais peut-être reformuler ma réponse de façon à ne jamais dire "jamais" . Je ne voulais pas dire qu'il est impossible de vérifier les valeurs π imprécises, mais simplement que se débarrasser des avertissements ne garantit pas une qualité de code décente.
Dmitry Grigoryev

Une chose vous avertit en tant qu'erreurs, c'est que les versions automatisées échoueront, vous alertant ainsi que quelque chose a mal tourné. Les versions automatisées permettent également d'automatiser les peluches (l'explosion est de 3 ... 2 ... 1 .. :)
Móż

8

En tant que personne travaillant avec du code C intégré hérité, l'activation des avertissements du compilateur a aidé à montrer beaucoup de faiblesses et de domaines à étudier lors de la proposition de correctifs. En utilisant gcc -Wallet -Wextraet même -Wshadowsont devenus essentiels. Je ne vais pas courir tous les dangers, mais je vais en énumérer quelques-uns qui ont surgi et qui ont aidé à montrer les problèmes de code.

Variables laissées pour compte

Celui-ci peut facilement indiquer des travaux inachevés et des domaines qui pourraient ne pas utiliser toutes les variables transmises, ce qui pourrait être un problème. Regardons une fonction simple qui peut déclencher ceci:

int foo(int a, int b)
{
   int c = 0;

   if (a > 0)
   {
        return a;
   }
   return 0;
}

La simple compilation sans -Wall ou -Wextra ne renvoie aucun problème. -Wall vous dira que cela cn'est jamais utilisé:

foo.c: Dans la fonction 'foo':

foo.c: 9: 20: avertissement: variable inutilisée 'c' [-Wunused-variable]

-Wextra vous indiquera également que votre paramètre b ne fait rien:

foo.c: Dans la fonction 'foo':

foo.c: 9: 20: avertissement: variable inutilisée 'c' [-Wunused-variable]

foo.c: 7: 20: avertissement: paramètre inutilisé 'b' [-Wunused-parameter] int foo (int a, int b)

Observation variable globale

Celui-ci est un peu dur et n'apparaît pas jusqu'à ce qu'il -Wshadowsoit utilisé. Modifions l'exemple ci-dessus pour simplement l'ajouter, mais il se trouve qu'il y a juste un global avec le même nom qu'un local, ce qui crée beaucoup de confusion lorsque vous essayez d'utiliser les deux.

int c = 7;

int foo(int a, int b)
{
   int c = a + b;
   return c;
}

Lorsque -Wshadow a été activé, il est facile de détecter ce problème.

foo.c: 11: 9: avertissement: la déclaration de 'c' masque une déclaration globale [-Wshadow]

foo.c: 1: 5: remarque: la déclaration fantôme est ici

Format des chaînes

Cela ne nécessite aucun indicateur supplémentaire dans gcc, mais cela a toujours été la source de problèmes dans le passé. Une fonction simple essayant d'imprimer des données, mais ayant une erreur de formatage pourrait ressembler à ceci:

void foo(const char * str)
{
    printf("str = %d\n", str);
}

Cela n'imprime pas la chaîne car l'indicateur de formatage est incorrect et gcc vous répondra avec plaisir ce n'est probablement pas ce que vous vouliez:

foo.c: Dans la fonction 'foo':

foo.c: 10: 12: avertissement: le format '% d' attend l'argument de type 'int', mais l'argument 2 a le type 'const char *' [-Wformat =]


Ce ne sont que trois des nombreuses choses que le compilateur peut vérifier pour vous. Il y en a beaucoup d'autres comme l'utilisation d'une variable non initialisée que d'autres ont souligné.


7
Dans le monde intégré, les avertissements qui m'inquiètent le plus sont les avertissements " possible loss of precision" et " comparison between signed and unsigned". J'ai du mal à comprendre combien de "programmeurs" les ignorent (en fait, je ne sais pas vraiment pourquoi ce ne sont pas des erreurs)
Mawg dit de réintégrer Monica le

3
Dans ce dernier cas, @Mawg, je pense que la principale raison pour laquelle il ne s'agit pas d'une erreur est que le résultat de sizeofn'est pas signé, mais le type entier par défaut est signé. Le sizeoftype de résultat,, size_test généralement utilisé pour tout élément lié à la taille du type, comme, par exemple, l'alignement ou le nombre d'éléments de tableau / conteneur, tandis que les entiers en général sont destinés à être utilisés comme " intsauf indication contraire". Compte tenu du nombre de personnes apprises à utiliser intpour parcourir leurs conteneurs (par rapport intà size_t), en faire une erreur briserait à peu près tout. ; P
Justin Time - Rétablir Monica le

6

Il s'agit d'une réponse spécifique à C, et pourquoi cela est beaucoup plus important pour C que pour toute autre chose.

#include <stdio.h>
int main()
{
   FILE *fp = "some string";
}

Ce code se compile avec un avertissement . Ce sont et devraient être des erreurs dans à peu près tous les autres langages de la planète (sauf langage d'assemblage) sont des avertissements en C. Les avertissements en C sont presque toujours des erreurs déguisées. Les avertissements doivent être corrigés et non supprimés.

Avec gcc, on fait ça comme gcc -Wall -Werror.

C'était également la raison de la forte répugnance de certains avertissements d'API non sécurisés MS. La plupart des gens qui programment C ont appris la manière difficile de traiter les avertissements comme des erreurs et ce truc est apparu que ce n'était tout simplement pas le même genre de chose et voulait des correctifs non portables.


5

LES AVERTISSEMENTS DU COMPILATEUR SONT VOTRE AMI (pas de cris, en majuscules pour souligner).

Je travaille sur les anciens systèmes Fortran-77. Le compilateur me dit des choses précieuses: le type de données d'argument ne correspond pas à un appel de sous-routine, en utilisant une variable locale avant qu'une valeur ait été définie dans la variable, si j'ai une variable ou un argument de sous-routine qui n'est pas utilisé. Ce sont presque toujours des erreurs.

Éviter un long post: Quand mon code compile proprement, 97% ça marche. L'autre gars avec qui je travaille compile avec tous les avertissements désactivés, passe des heures ou des jours dans le débogueur, puis me demande de l'aider. Je viens de compiler son code avec les avertissements et de lui dire quoi corriger.


5

Vous devez toujours activer les avertissements du compilateur car le compilateur peut souvent vous dire ce qui ne va pas avec votre code. Pour ce faire, vous passez -Wall -Wextraau compilateur.

Vous devez généralement traiter les avertissements comme des erreurs, car les avertissements signifient généralement qu'il y a un problème avec votre code. Cependant, il est souvent très facile d'ignorer ces erreurs. Par conséquent, les traiter comme des erreurs entraînera l'échec de la génération, vous ne pouvez donc pas ignorer les erreurs. Pour traiter les avertissements comme des erreurs, passez -Werrorau compilateur.


4

Les avertissements du compilateur en C ++ sont très utiles pour certaines raisons.

1 - Il permet de vous montrer où vous pouvez avoir commis une erreur qui peut impacter le résultat final de vos opérations. Par exemple si vous n'avez pas initialisé une variable ou si vous mettez "=" au lieu de "==" (il y a juste des exemples)

2 - Il permet également de vous montrer où votre code n'est pas conforme au standard du c ++. C'est utile car si le code est conforme à la norme actuelle, il sera facile de déplacer le code dans une autre plateforme par exemple.

En général, les avertissements sont très utiles pour vous montrer où vous avez des erreurs dans votre code qui peuvent affecter le résultat de votre algorithme ou empêcher une erreur lorsque l'utilisateur utilisera votre programme.


4

Ignorer les avertissements signifie que vous avez laissé du code bâclé qui pourrait non seulement causer des problèmes à l'avenir à quelqu'un d'autre, mais aussi rendre les messages de compilation importants moins remarqués par vous. Plus il y a de sortie du compilateur, moins personne ne le remarquera ou ne le dérangera. Plus propre, mieux c'est. Cela signifie également que vous savez ce que vous faites. Les avertissements sont très peu professionnels, imprudents et risqués.


4

J'ai déjà travaillé pour une grande entreprise (Fortune 50) qui fabriquait du matériel de test électronique.

Le produit de base de mon groupe était un programme MFC qui, au fil des ans, est venu générer littéralement des centaines d'avertissements. Qui ont été ignorés dans presque tous les cas.

C'est un cauchemar dérangeant quand des bugs se produisent.

Après ce poste, j'ai eu la chance d'être embauché en tant que premier développeur d'une nouvelle startup.

J'ai encouragé une politique «sans avertissement» pour toutes les versions, avec des niveaux d'avertissement du compilateur définis pour être assez bruyants.

Notre pratique consistait à utiliser #pragma warning - push / disable / pop pour le code que le développeur était sûr était très bien, avec une instruction de journal au niveau du débogage, juste au cas où.

Cette pratique a bien fonctionné pour nous.


1
Appuyé. #pragma warningne supprime pas seulement les avertissements, il sert le double objectif de communiquer rapidement aux autres programmeurs que quelque chose est intentionnel et non accidentel, et agit comme une balise de recherche pour localiser rapidement les zones potentiellement problématiques lorsque quelque chose se casse, mais la correction des erreurs / avertissements ne le fait pas répare le.
Justin Time - Rétablir Monica

Tu as raison Justin, c'est exactement ainsi que j'ai vu l'avertissement #pragma
Jim In Texas

3

Un avertissement est une erreur qui attend de se produire. Vous devez donc activer les avertissements du compilateur et ranger votre code pour supprimer tout avertissement.


3

Il n'y a qu'un seul problème à traiter les avertissements comme des erreurs: lorsque vous utilisez du code provenant d'autres sources (par exemple, des bibliothèques micro $ ** t, des projets open source), ils n'ont pas fait leur travail correctement, et la compilation de leur code génère des tonnes d'avertissements.

Je toujours écrire mon code afin qu'il ne génère pas d'avertissement ou d' erreurs, et le nettoyer jusqu'à ce qu'il compile sans générer aucun bruit parasite. Les ordures avec lesquelles je dois travailler m'épouvante, et je suis étonné quand je dois construire un gros projet et regarder un flux d'avertissements passer par où la compilation ne devrait annoncer que les fichiers qu'elle a traités.

Je documente également mon code parce que je sais que le coût réel des logiciels à vie vient principalement de la maintenance, pas de l'écriture initiale, mais c'est une autre histoire ...


Ne le cognez pas, il y a beaucoup d'argent dans le travail de consultation pour les personnes qui peuvent lire les avertissements du compilateur à haute voix aux clients.
Móż

Le code provenant d'autres sources générant des avertissements ne signifie pas nécessairement que les auteurs étaient bâclés. Cela peut également signifier qu'ils ont compilé le code avec un compilateur différent qui a généré un ensemble différent d'avertissements. Le code peut compiler sans avertissements sur un compilateur et générer des avertissements sur un autre. Ou peut-être qu'il s'agit simplement d'un ensemble différent d'options d'avertissement; par exemple, ils ont utilisé -Wallet vous utilisez -Wall -Wextra.
celtschk

2

Un avertissement peut signifier une possible erreur sémantique dans le code ou une éventuelle UB. Par exemple ;aprèsif() , variable inutilisée, variable globale masquée par local, ou comparaison de signé et non signé. De nombreux avertissements sont liés à l'analyseur de code statique dans le compilateur ou aux violations de la norme ISO détectables au moment de la compilation, qui "nécessitent des diagnostics". Bien que ces événements puissent être légaux dans un cas particulier, ils résulteraient la plupart du temps de problèmes de conception.

Certains compilateurs, par exemple gcc, ont une option en ligne de commande pour activer le mode "avertissements en tant qu'erreurs", c'est un bel outil, si cruel, pour éduquer les codeurs débutants.


1

Le fait que les compilateurs C acceptent la compilation du code qui évidemment conduit à un comportement non défini à tous est un défaut majeur dans les compilateurs. La raison pour laquelle ils ne résolvent pas cela est que cela casserait probablement certaines versions utilisables.

La plupart des avertissements doivent être des erreurs fatales qui empêchent la génération de se terminer. Les valeurs par défaut pour afficher uniquement les erreurs et faire la construction de toute façon sont erronées et si vous ne les remplacez pas pour traiter les avertissements comme des erreurs et laisser des avertissements, vous vous retrouverez probablement avec le plantage de votre programme et des actions aléatoires.


Ironiquement, beaucoup de comportements indéfinis ne provoquent pas réellement d'avertissements, mais se compilent parfaitement en une petite bombe à retardement. ; P
Justin Time - Réintègre Monica

1
Le problème est que si la norme exige un message d'erreur, ce message d'erreur doit être émis dans tous les cas où le problème se produit, mais jamais si le problème ne se produit pas. Mais dans des cas comme un comportement indéfini, cela peut être impossible à décider. Par exemple, considérez le code suivant: int i; if (fun1()) i=2; if (fun2()) i=3; char s="abcde"[i];Ce code présente un comportement indéfini si et seulement si les deux fun1()et fun2()peuvent retourner falsesur la même exécution de fonction. Laquelle peut être vraie ou non, mais comment le compilateur le dira-t-il?
celtschk

-2

Vous devez certainement activer les avertissements du compilateur, car certains compilateurs ne parviennent pas à signaler certaines erreurs de programmation courantes, notamment les suivantes: -

-> l'initialisation d'une variable est oubliée -> le retour d'une valeur d'une fonction est oublié -> les arguments simples dans les familles printf et scanf ne correspondant pas à la chaîne de formatage une fonction est utilisée sans être déclarée au préalable, mais ne se produit qu'en c

Donc, comme ces fonctions peuvent être détectées et signalées, ce n'est généralement pas le cas par défaut; cette fonctionnalité doit donc être explicitement demandée via les options du compilateur.


-32

Allez-y doucement: vous n'êtes pas obligé, ce n'est pas nécessaire. -Wall et -Werror ont été conçus par des maniaques de refactorisation de code pour eux-mêmes: ils ont été inventés par les développeurs de compilateurs pour éviter de casser les builds existants après les mises à jour du compilateur côté utilisateur . La fonctionnalité n'est rien, mais tout sur la décision de casser ou de ne pas casser la build.

C'est entièrement à votre préférence de l'utiliser ou non. Je l'utilise tout le temps car cela m'aide à corriger mes erreurs.


19
Bien que ce ne soit pas obligatoire , il est fortement recommandé de les utiliser
Spikatrix

18
-Wall and -Werror was designed by code-refactoring maniacs for themselves.[citation nécessaire]
YSC

22
Il semble que vous vous contredisez. Si vous "l'utilisez tout le temps parce que cela aide à corriger [vos] erreurs", ne vaut-il pas la peine d'enseigner aux nouveaux programmeurs pour qu'ils le fassent partout dès le départ? Je ne pense pas que cette question demande si oui ou non il est possible de compiler sans -Wallet -Werror, il demande simplement si elle est une bonne idée. Ce qui, d'après votre dernière phrase, semble que vous le dites.
scohe001

12
Lorsque vous aurez plus d'expérience dans la gestion du code que vous n'avez pas écrit, revoyez cette réponse.
Thorbjørn Ravn Andersen

Ce n'est pas une réponse utile. Il y a 4 points d'interrogation dans la question OP. À combien cette réponse répond-elle?
Anders
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.