Warum sollte ich Compiler-Warnungen immer aktivieren?


302

Ich höre oft, dass ich beim Kompilieren von C- und C ++ - Programmen "immer Compiler-Warnungen aktivieren" sollte. Warum ist das notwendig? Wie mache ich das?

Manchmal höre ich auch, dass ich "Warnungen als Fehler behandeln soll". Sollte ich? Wie mache ich das?

Antworten:


341

Warum Warnungen aktivieren?

C- und C ++ - Compiler sind bekanntermaßen schlecht darin, einige häufige Programmiererfehler standardmäßig zu melden , wie z.

  • Vergessen, eine Variable zu initialisieren
  • Vergessen returneines Wertes aus einer Funktion
  • Argumente in printfund scanfFamilien, die nicht mit der Formatzeichenfolge übereinstimmen
  • Eine Funktion wird verwendet, ohne vorher deklariert zu werden (nur C).

Diese können erkannt und gemeldet werden, normalerweise jedoch nicht standardmäßig. Diese Funktion muss explizit über Compileroptionen angefordert werden.

Wie aktiviere ich Warnungen?

Dies hängt von Ihrem Compiler ab.

Microsoft C und C ++ Compiler verstehen Schalter wie /W1, /W2, /W3, /W4und /Wall. Verwenden Sie mindestens /W3. /W4und /Wallkann falsche Warnungen für Systemheaderdateien ausgeben, aber wenn Ihr Projekt mit einer dieser Optionen sauber kompiliert wird, versuchen Sie es. Diese Optionen schließen sich gegenseitig aus.

Die meisten anderen Compilern verstehen Optionen wie -Wall, -Wpedanticund -Wextra. -Wallist wichtig und alle anderen werden empfohlen (beachten Sie, dass trotz des Namens -Wallnur die wichtigsten Warnungen aktiviert werden, nicht alle ). Diese Optionen können einzeln oder alle zusammen verwendet werden.

Ihre IDE kann diese möglicherweise über die Benutzeroberfläche aktivieren.

Warum Warnungen als Fehler behandeln? Sie sind nur Warnungen!

Eine Compiler-Warnung weist auf ein möglicherweise schwerwiegendes Problem in Ihrem Code hin. Die oben aufgeführten Probleme sind fast immer tödlich. andere können es sein oder auch nicht, aber Sie möchten, dass die Kompilierung fehlschlägt, auch wenn sich herausstellt, dass es sich um einen Fehlalarm handelt. Untersuchen Sie jede Warnung, finden Sie die Grundursache und beheben Sie sie. Umgehen Sie im Falle eines Fehlalarms das Problem, indem Sie eine andere Sprachfunktion oder ein anderes Konstrukt verwenden, damit die Warnung nicht mehr ausgelöst wird. Wenn sich dies als sehr schwierig herausstellt, deaktivieren Sie diese bestimmte Warnung von Fall zu Fall.

Sie möchten Warnungen nicht einfach als Warnungen belassen, auch wenn es sich bei allen um Fehlalarme handelt. Es könnte für sehr kleine Projekte in Ordnung sein, bei denen die Gesamtzahl der ausgegebenen Warnungen weniger als 7 beträgt. Alles andere und es ist leicht, dass eine neue Warnung in einer Flut von alten vertrauten Warnungen verloren geht. Erlaube das nicht. Lassen Sie einfach Ihr gesamtes Projekt sauber kompilieren.

Beachten Sie, dass dies für die Programmentwicklung gilt. Wenn Sie Ihr Projekt in der Quellform für die Welt freigeben, ist es möglicherweise eine gute Idee, -WerrorIhr veröffentlichtes Build-Skript nicht oder nicht gleichwertig bereitzustellen. Möglicherweise wird versucht, Ihr Projekt mit einer anderen Version des Compilers oder mit einem anderen Compiler zu erstellen, für den möglicherweise andere Warnungen aktiviert sind. Möglicherweise möchten Sie, dass ihr Build erfolgreich ist. Es ist immer noch eine gute Idee, die Warnungen aktiviert zu lassen, damit Personen, die Warnmeldungen sehen, Ihnen Fehlerberichte oder Patches senden können.

Wie werden Warnungen als Fehler behandelt?

Dies geschieht wiederum mit Compiler-Switches. /WXist für Microsoft, die meisten anderen verwenden -Werror. In beiden Fällen schlägt die Kompilierung fehl, wenn Warnungen ausgegeben werden.


107
Ich habe diese Fragen und Antworten veröffentlicht, weil ich es satt habe, Leuten zu sagen, dass sie Warnungen aktivieren sollen. Jetzt kann ich sie hier nur zeigen (oder, wenn ich besonders schlecht gelaunt bin, ihre Frage als Betrüger schließen). Sie können diese Antwort gerne verbessern oder Ihre eigene hinzufügen!
n. 'Pronomen' m.

16
Sie können auch clang's -Weverything
pmg

9
Der einzige Modifikator, den ich hinzufügen möchte, ist, dass einige Warnungen für Ihre Anwendung möglicherweise nicht hilfreich sind. (Ich habe Warnungen gesehen, dass der Compiler 2 Byte Auffüllen zwischen Elementen in einer Struktur hinzugefügt hat. Die Anwendung war für das Prototyping vorgesehen, daher hat uns ein wenig verschwendeter Speicher nicht gestört.) Behandeln Sie alle Warnungen als Fehler und deaktivieren Sie dann nur eine Warnung, wenn Sie wissen, warum diese Warnung Ihnen nicht hilft.
Kyle A

20
Der Nachteil der Behandlung von Warnungen als Fehler für Benutzer, die Ihre Standard-Build-Anweisungen befolgen, besteht darin, dass Ihr Code als Compiler verrottet und neue Warnungen hinzufügt. Benutzer, die Ihren Code herunterladen und versuchen, ihn in Zukunft zu erstellen, können dies möglicherweise nicht, da ihr Compiler zu neu ist und eine Warnung vor zusätzlichen Klammern oder etwas ausgibt, das Ihrem Compiler egal war. Der Benutzer, der auf den Fehler stößt, ist nicht für Ihren Code oder Ihr Build-System verantwortlich und hat keine Ahnung, wie Sie die Behandlung von Warnungen als Fehler deaktivieren und Ihr Projekt tatsächlich erstellen können.
Schnittstelle

15
@interfect Ja, das ist mir ein paar Mal passiert. Kein Problem. Wenn Sie sich dafür entschieden haben, eine nicht gewartete Software mit einem Compiler zu erstellen, mit dem sie nie getestet wurde, sollten Sie besser darauf vorbereitet sein, selbst einige Wartungsarbeiten durchzuführen.
n. 'Pronomen' m.

94

C ist bekanntlich eine eher einfache Sprache, wenn es um HLLs geht. C ++ scheint zwar eine wesentlich höhere Sprache als C zu sein, weist jedoch einige seiner Merkmale auf. Und eines dieser Merkmale ist, dass die Sprachen von Programmierern für Programmierer entwickelt wurden - und insbesondere von Programmierern, die wussten, was sie taten.

[Für den Rest dieser Antwort werde ich mich auf C konzentrieren. Das meiste, was ich sagen werde, gilt auch für C ++, wenn auch vielleicht nicht so stark. Obwohl, wie Bjarne Stroustrup berühmt gesagt hat: "C macht es einfach, sich in den Fuß zu schießen; C ++ macht es schwieriger, aber wenn Sie es tun, bläst es Ihr ganzes Bein ab." ]]

Wenn Sie wissen, was Sie tun - wirklich wissen, was Sie tun - müssen Sie manchmal "die Regeln brechen". Aber die meiste Zeit werden die meisten von uns zustimmen, dass gut gemeinte Regeln uns alle aus Ärger heraushalten und dass es eine schlechte Idee ist, diese Regeln ständig zu brechen.

Aber in C und C ++ gibt es überraschend viele Dinge, die Sie tun können, die "schlechte Ideen" sind, die aber formal nicht "gegen die Regeln" sind. Manchmal sind sie manchmal eine schlechte Idee (aber manchmal können sie verteidigt werden); Manchmal sind sie fast immer eine schlechte Idee. Aber die Tradition war immer, nicht vor diesen Dingen zu warnen - denn wiederum wird davon ausgegangen, dass Programmierer wissen, was sie tun, sie würden diese Dinge nicht ohne guten Grund tun, sie würden sich über einen Haufen ärgern von unnötigen Warnungen.

Aber natürlich wissen nicht alle Programmierer wirklich , was sie tun. Insbesondere durchläuft jeder C-Programmierer (egal wie erfahren) eine Phase, in der er ein beginnender C-Programmierer ist. Und selbst erfahrene C-Programmierer können nachlässig werden und Fehler machen.

Schließlich hat die Erfahrung nicht nur gezeigt, dass Programmierer Fehler machen, sondern dass diese Fehler echte, schwerwiegende Folgen haben können. Wenn Sie einen Fehler machen und der Compiler Sie nicht davor warnt und das Programm nicht sofort abstürzt oder etwas offensichtlich Falsches tut, kann der Fehler dort lauern, manchmal jahrelang versteckt, bis er verursacht ein wirklich großes Problem.

Es stellt sich also heraus, dass Warnungen meistens eine gute Idee sind. Sogar die erfahrenen Programmierer haben gelernt (tatsächlich haben " besonders die erfahrenen Programmierer gelernt"), dass die Warnungen insgesamt mehr Gutes als Schaden anrichten. Für jedes Mal, wenn Sie absichtlich etwas falsch gemacht haben und die Warnung ein Ärgernis war, haben Sie wahrscheinlich mindestens zehn Mal versehentlich etwas falsch gemacht, und die Warnung hat Sie vor weiteren Problemen bewahrt. Und die meisten Warnungen können für die wenigen Male deaktiviert oder umgangen werden, wenn Sie wirklich das "Falsche" tun möchten.

(Ein klassisches Beispiel für eine solche „Fehler“ ist der Test Die if(a = b)meiste Zeit, ist dies ein Fehler ist, so dass die meisten Compiler in diesen Tagen darüber warnen -.. Einige sogar standardmäßig Aber wenn Sie wirklich sowohl assign wollte bzu aund Test Im Ergebnis können Sie die Warnung durch Eingabe deaktivieren if((a = b)).)

Die zweite Frage ist, warum Sie den Compiler bitten möchten, Warnungen als Fehler zu behandeln. Ich würde sagen, es liegt an der menschlichen Natur, insbesondere an der allzu einfachen Reaktion, zu sagen: "Oh, das ist nur eine Warnung, das ist nicht so wichtig, ich werde das später aufräumen." Aber wenn Sie ein Zauderer sind (und ich weiß nichts über Sie, aber ich bin ein schrecklicher Zauderer), ist es einfach, die notwendige Bereinigung für immer zu verschieben - und wenn Sie es sich zur Gewohnheit machen, Warnungen zu ignorieren, dann Es wird immer einfacher, eine wichtige Warnmeldung zu übersehen , die unbemerkt inmitten all derer liegt, die Sie ignorieren.

Den Compiler zu bitten, Warnungen als Fehler zu behandeln, ist ein kleiner Trick, den Sie selbst spielen können, um diese menschliche Schwäche zu umgehen.

Persönlich bestehe ich nicht so darauf, Warnungen als Fehler zu behandeln. (In der Tat, wenn ich ehrlich bin, kann ich sagen, dass ich diese Option in meiner "persönlichen" Programmierung praktisch nie aktiviere.) Aber Sie können sicher sein, dass ich diese Option bei der Arbeit aktiviert habe, wo unser Styleguide (den ich schrieb) beauftragt seine Verwendung. Und ich würde sagen - ich vermute, die meisten professionellen Programmierer würden sagen -, dass jeder Shop, der Warnungen nicht als Fehler in C behandelt, sich verantwortungslos verhält und sich nicht an allgemein anerkannte Best Practices der Branche hält.


9
"Programmierer, die wussten, was sie taten" - LOL; Es gibt einen "no true Scotsman"
-Fehler,

3
@Dancrumb LOL zurück atcha. Ich bin mir nie ganz sicher, ob ich den No True Scotsman- Irrtum verstehe , aber ich mag ihn, also wird dies eine gute Übung für mich sein. Ich denke, die Anwendung hier sieht folgendermaßen aus: "Kein C-Programmierer würde jemals schreiben if(a = b), daher müssen wir nicht davor warnen." (Dann erstellt jemand eine Liste von 10 kritischen Fehlern in 10 veröffentlichten Produkten, die aus diesem speziellen Fehler resultieren.) "Okay, kein erfahrener C-Programmierer würde das jemals schreiben ..."
Steve Summit

3
@SteveSummit, aber ein wirklich erfahrener C-Programmierer kann es schreiben if (returnCodeFromFoo = foo(bar))und meinen, um den Code an einem Ort zu erfassen und zu testen (Angenommen, der einzige Zweck foobesteht darin, Nebenwirkungen zu haben!). Die Tatsache, dass ein wirklich wirklich erfahrener Programmierer weiß, dass dies kein Problem ist Guter Codierungsstil ist
nebensächlich

5
Die Sache ist, dass die meisten sehr erfahrenen Programmierer die meisten, wenn nicht alle Warnungen aktivieren. Wenn sie so etwas verwenden möchten if (returnCodeFromFoo = foo(bar)), geben sie einen Kommentar ein und deaktivieren die Warnung (sodass der Wartungsprogrammierer 4 Jahre später erkennt, dass der Code beabsichtigt ist. Das heißt, ich habe gearbeitet mit jemandem, der in (in Microsoft C ++) darauf bestand, dass das Kombinieren von / Wall mit dem Behandeln von Warnungen als Fehler der
richtige

3
Als jemand, der nicht täglich Code schreibt, aber wenn ich es tue, ist es meistens Bare Metal (oft auf einem Board meines eigenen Designs), finde ich Warnungen von unschätzbarem Wert. Wenn Werte in interne Register eingefügt werden (ein Beispiel für eine DMA-Deskriptorposition), bedeutet die Warnung zur Konvertierung in einen Zeiger, dass ich einen Cast mache, um die Warnung zu löschen. Es wäre kein Fehler, aber wenn jemand anderes (oder sogar ich selbst!) Diesen Code in ein paar Monaten aufgreift, könnte dies durchaus verwirrend sein. Außerdem wende ich die Regel "Keine Warnungen vorhanden" auch auf die Ausgaben meiner CAD-Werkzeuge an.
Peter Smith

39

Warnungen bestehen aus den besten Ratschlägen, die einige der erfahrensten C ++ - Entwickler in eine Anwendung einbinden könnten. Sie sind es wert, hier zu bleiben.

C ++ ist eine vollständige Turing-Sprache und hat viele Fälle, in denen der Compiler einfach darauf vertrauen muss, dass Sie wissen, was Sie tun. Es gibt jedoch viele Fälle, in denen der Compiler erkennen kann, dass Sie wahrscheinlich nicht beabsichtigten, das zu schreiben, was Sie geschrieben haben. Ein klassisches Beispiel sind printf () - Codes, die nicht mit den Argumenten übereinstimmen, oder an printf übergebene std :: strings (nicht, dass mir das jemals passiert!). In diesen Fällen ist der von Ihnen geschriebene Code kein Fehler. Es ist ein gültiger C ++ - Ausdruck mit einer gültigen Interpretation, auf die der Compiler reagieren kann. Der Compiler hat jedoch die starke Vermutung, dass Sie einfach etwas übersehen haben, das für einen modernen Compiler leicht zu erkennen ist. Dies sind Warnungen. Dies sind Dinge, die für einen Compiler offensichtlich sind, wenn er alle strengen Regeln von C ++ verwendet, die Sie möglicherweise übersehen haben.

Das Deaktivieren oder Ignorieren von Warnungen ist wie das Ignorieren von kostenlosen Ratschlägen von Fachleuten als Ihnen. Es ist eine Lektion in Huberis, die entweder endet, wenn Sie zu nahe an der Sonne fliegen und Ihre Flügel schmelzen, oder wenn ein Speicherfehler auftritt. Zwischen den beiden werde ich jeden Tag vom Himmel fallen!

"Warnungen als Fehler behandeln" ist die extreme Version dieser Philosophie. Die Idee dabei ist, dass Sie jede Warnung des Compilers auflösen - Sie hören sich jeden kostenlosen Rat an und handeln danach. Ob dies ein gutes Entwicklungsmodell für Sie ist, hängt vom Team und der Art des Produkts ab, an dem Sie arbeiten. Es ist der asketische Ansatz, den ein Mönch haben könnte. Für einige funktioniert es großartig. Für andere nicht.

In vielen meiner Anwendungen behandeln wir Warnungen nicht als Fehler. Wir tun dies, weil diese speziellen Anwendungen auf mehreren Plattformen mit mehreren Compilern unterschiedlichen Alters kompiliert werden müssen. Manchmal stellen wir fest, dass es tatsächlich unmöglich ist, eine Warnung auf einer Seite zu korrigieren, ohne dass daraus eine Warnung auf einer anderen Plattform wird. Wir sind also nur vorsichtig. Wir respektieren Warnungen, aber wir beugen uns für sie nicht nach hinten.


11
Was hat C ++ als Turing komplett damit zu tun? Viele Sprachen sind vollständig und vertrauen Ihnen nicht, wenn Sie etwas falsch machen ...
Auf Wiedersehen SE

3
@KamiKaze Jede Sprache weist idiomatische Fehler auf (z. B. Java kann Sie nicht davon abhalten, ein inkonsistentes equals/ zu schreiben hashCode), und es handelt sich um ein Problem mit der Qualität der Implementierung, über das berichtet wird.
Caleth

2
@KamiKaze Das Turing-Vollständigkeitsbit zeigt an, dass es Fälle gibt, in denen der Compiler nicht nachweisen kann, dass Ihr Code nicht wie geplant funktioniert. Dies ist wichtig, da Compiler nicht jeden "falschen" Code zu einem Fehler machen können. Fehler können nur für Verhaltensweisen reserviert werden, von denen die Sprachdesigner sicher sind, dass sie immer "falsch" sind. (normalerweise, weil es inkonsistente Pfade hinunterführt).
Cort Ammon

2
Was auch auf die Herausforderung mit "Alle Warnungen sind Fehler" hinweist. Warnungen sind von Natur aus opportunistischer und lösen potenziell korrekten Code aus, wenn sie häufiger falschen Code auslösen. Warnungen als Fehler führen dazu, dass Sie nicht alle Funktionen der Sprache nutzen können.
Cort Ammon

2
Im Allgemeinen wollen Programmierer jedoch eine Sprache, die mehr als nur "sicher" ist. Wir wollen eine Sprache, die das tut, was wir uns gesagt haben. Daher bleiben Warnungen wichtig, da die eigentliche Klasse von Dingen, die der Computer ausführen soll, eine semantische Klasse ist. Der Compiler kann es durch Definieren von "falsch" oder "unsicher" herausfinden, aber am Ende haben Sie immer noch eine Oberklasse der Verhaltensweisen, die der Programmierer vom Programm wollte. Warnungen helfen dabei, diese Oberklasse einzugrenzen.
Cort Ammon

19

Der Umgang mit den Warnungen macht nicht nur den Code besser, sondern macht Sie auch zu einem besseren Programmierer. Warnungen werden Sie über Dinge informieren, die Ihnen heute vielleicht wenig erscheinen, aber eines Tages wird diese schlechte Angewohnheit zurückkommen und Ihnen den Kopf abbeißen.

Verwenden Sie den richtigen Typ, geben Sie diesen Wert zurück und bewerten Sie diesen Rückgabewert. Nehmen Sie sich Zeit und überlegen Sie: "Ist das in diesem Zusammenhang wirklich der richtige Typ?" "Muss ich das zurückgeben?" Und der Biggie; "Wird dieser Code in den nächsten 10 Jahren portabel sein?"

Gewöhnen Sie sich an, in erster Linie warnfreien Code zu schreiben.


17

Die anderen Antworten sind ausgezeichnet und ich möchte nicht wiederholen, was sie gesagt haben.

Ein weiterer Aspekt von "Warum Warnungen aktivieren", der nicht richtig angesprochen wurde, ist, dass sie bei der Codepflege enorm helfen. Wenn Sie ein Programm von beträchtlicher Größe schreiben, wird es unmöglich, das Ganze auf einmal im Kopf zu behalten. Normalerweise haben Sie eine oder drei Funktionen, über die Sie aktiv schreiben und nachdenken, und möglicherweise eine oder drei Dateien auf Ihrem Bildschirm, auf die Sie verweisen können, aber der Großteil des Programms befindet sich irgendwo im Hintergrund, und Sie müssen darauf vertrauen arbeitet weiter.

Wenn Sie Warnungen aktiviert haben und diese so energisch und in Ihrem Gesicht wie möglich haben, können Sie benachrichtigt werden, wenn etwas, das Sie ändern, Probleme mit etwas verursacht, das Sie nicht sehen können.

Nehmen Sie zum Beispiel die Klirrwarnung -Wswitch-enum. Dies löst eine Warnung aus, wenn Sie einen Schalter für eine Aufzählung verwenden und einen der möglichen Aufzählungswerte verpassen. Es ist etwas, von dem Sie vielleicht denken, dass es ein unwahrscheinlicher Fehler ist: Sie haben sich wahrscheinlich zumindest die Liste der Enum-Werte angesehen, als Sie die switch-Anweisung geschrieben haben. Möglicherweise haben Sie sogar eine IDE, die die Switch-Optionen für Sie generiert hat und keinen Raum für menschliches Versagen lässt.

Diese Warnung kommt wirklich zur Geltung, wenn Sie sechs Monate später einen weiteren möglichen Eintrag in die Aufzählung aufnehmen. Wenn Sie über den fraglichen Code nachdenken, wird es Ihnen wahrscheinlich gut gehen. Wenn diese Aufzählung jedoch für mehrere verschiedene Zwecke verwendet wird und für einen der Zwecke, für die Sie die zusätzliche Option benötigen, können Sie leicht vergessen, einen Schalter in einer Datei zu aktualisieren, die Sie seit 6 Monaten nicht mehr berührt haben.

Sie können sich Warnungen genauso vorstellen wie automatisierte Testfälle: Sie helfen Ihnen, sicherzustellen, dass der Code sinnvoll ist und tun, was Sie beim ersten Schreiben benötigen, aber sie helfen noch mehr, dies sicherzustellen macht weiter, was du brauchst, während du daran stößt. Der Unterschied besteht darin, dass Testfälle sehr eng an den Anforderungen Ihres Codes arbeiten und Sie diese schreiben müssen, während Warnungen für fast den gesamten Code weitgehend nach vernünftigen Standards funktionieren und von den Boffins, die die Compiler erstellen, sehr großzügig bereitgestellt werden.


9
Die andere Art und Weise, wie sie bei der Wartung helfen, besteht darin, dass Sie sich den Code einer anderen Person ansehen und nicht feststellen können, ob eine Nebenwirkung beabsichtigt war. Wenn Warnungen aktiviert sind, wissen Sie, dass sie sich des Problems zumindest bewusst waren.
Robin Bennett

In meinem Fall importieren Sie eine Datei aus einem eingebetteten System, das eine Switch-Anweisung mit mehr als 3000 Zeilen über eine Aufzählung mit mehreren tausend Werten enthält. Die "Falls Through" -Warnungen (vermieden durch die Verwendung von goto) maskierten eine Reihe von "nicht behandelten" Fehlern ... der eingebettete Compiler gab keinen dieser Fehler aus, aber die Fehler waren trotzdem wichtig.
Móż

15

Nicht festgelegte Warnungen führen früher oder später zu Fehlern in Ihrem Code .


Zum Debuggen eines Segmentierungsfehlers muss der Programmierer beispielsweise die Ursache des Fehlers verfolgen, die sich normalerweise an einer früheren Stelle in Ihrem Code befindet als die Zeile, die schließlich den Segmentierungsfehler verursacht hat.

Es ist sehr typisch, dass die Ursache eine Zeile ist, für die der Compiler eine Warnung ausgegeben hat, die Sie ignoriert haben, und die Zeile, die den Segmentierungsfehler verursacht hat, die Zeile, die schließlich den Fehler ausgelöst hat.

Das Beheben der Warnung führt zum Beheben des Problems. Ein Klassiker!

Eine Demonstration des oben genannten. Betrachten Sie den folgenden Code:

#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;
}

was beim Kompilieren mit dem an GCC übergebenen "Wextra" -Flag ergibt:

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

was ich sowieso ignorieren und den Code ausführen könnte . Und dann würde ich einen "großen" Segmentierungsfehler erleben, wie mein IP-Epicurus-Professor sagte:

Segmentierungsfehler

Um dies in einem realen Szenario zu debuggen, würde man von der Zeile ausgehen, die den Segmentierungsfehler verursacht, und versuchen, die Ursache der Ursache zu ermitteln. Sie müssten nach dem suchen, was mit iund strinnerhalb dieser kolossalen Menge geschehen ist von Code dort drüben ...

Bis sie sich eines Tages in der Situation befanden, in der sie entdeckten, dass idxsie nicht initialisiert verwendet wird, hat sie einen Müllwert , der dazu führt, dass die Zeichenfolge (weit) außerhalb ihrer Grenzen indiziert wird, was zu einem Segmentierungsfehler führt.

Wenn sie die Warnung nur nicht ignoriert hätten, hätten sie den Fehler sofort gefunden!


4
Zu Ihrem Titel: nicht unbedingt. Eine Warnung, die vorschlägt, Klammern in einer Formel zu verwenden, die sie wirklich nicht benötigt, weist beispielsweise auf ein Problem hin, das niemals einen Fehler verursachen wird. Operator-Prioritäten in einer bestimmten Programmiersprache ändern sich nicht. Je.
Marc van Leeuwen

4
@MarcvanLeeuwen Die von Ihnen angegebene Instanz kann sich in einen Fehler verwandeln, wenn beispielsweise der Programmierer, der sich nicht an die Priorität des Operators erinnert, die Formel ein wenig korrekt ändert. Die Warnung sagt Ihnen: "Es könnte jemandem irgendwann unklar sein, fügen Sie einige Klammern hinzu, um es klarer zu machen." Obwohl man zustimmen muss, dass der Titel des ursprünglichen Beitrags nicht immer wahr ist.
Hubert Jasieniecki

^ Alles kann in einen Fehler verwandelt werden. Es ist genauso einfach, einen Fehler in teilweise in Klammern gesetzten Code einzufügen wie in vollständig in Klammern gesetzten Code.
Jim Balter

... Als Nebenwirkung , ich habe Fragen für den Debugger , deren erste Reaktion auf „Oh, es segfaulted aus str[idx]ist nicht „Okay, wo sind strund idxdefiniert`?
Justin Time - wieder einzusetzen Monica

2
Sie haben Glück, wenn Sie einen Segmentierungsfehler erhalten. Wenn Sie weniger Glück haben, haben Sie möglicherweise zufällig idxden Wert, den Sie für Ihren Test erwartet haben (nicht zu unwahrscheinlich, wenn der erwartete Wert 0 ist), und verweisen tatsächlich auf einige vertrauliche Daten, die bei der Bereitstellung niemals gedruckt werden sollten.
Celtschk

14

Warnungen als Fehler zu behandeln ist nur ein Mittel der Selbstdisziplin: Sie haben ein Programm kompiliert, um diese glänzende neue Funktion zu testen, aber Sie können es nicht, bis Sie die schlampigen Teile repariert haben. Es gibt keine zusätzlichen Informationen Werror, sondern nur sehr klare Prioritäten:

Fügen Sie keinen neuen Code hinzu, bis Sie Probleme im vorhandenen Code behoben haben

Es ist wirklich die Denkweise, die wichtig ist, nicht die Werkzeuge. Die Compiler-Diagnoseausgabe ist ein Werkzeug. MISRA (für Embedded C) ist ein weiteres Tool. Es spielt keine Rolle, welches Sie verwenden, aber Compiler-Warnungen sind wohl das einfachste Tool, das Sie erhalten können (es ist nur ein Flag zum Setzen), und das Signal-Rausch-Verhältnis ist sehr hoch. Es gibt also keinen Grund, es nicht zu benutzen.

Kein Werkzeug ist unfehlbar. Wenn Sie schreiben const float pi = 3.14;, sagen Ihnen die meisten Tools nicht, dass Sie π mit einer schlechten Genauigkeit definiert haben, was später zu Problemen führen kann. Die meisten Tools ziehen keine Augenbrauen hoch if(tmp < 42), auch wenn allgemein bekannt ist, dass die Angabe von bedeutungslosen Namen für Variablen und die Verwendung magischer Zahlen eine Möglichkeit ist, in großen Projekten eine Katastrophe zu verursachen. Sie müssen verstehen, dass jeder "Schnelltest" -Code, den Sie schreiben, genau das ist: ein Test, und Sie müssen ihn richtig machen, bevor Sie mit anderen Aufgaben fortfahren, während Sie immer noch seine Mängel sehen. Wenn Sie diesen Code unverändert lassen, wird das Debuggen erheblich schwieriger, wenn Sie nach zwei Monaten neue Funktionen hinzufügen.

Sobald Sie die richtige Einstellung gefunden haben, macht es keinen Sinn, sie zu verwenden Werror. Wenn Sie Warnungen als Warnungen haben, können Sie eine fundierte Entscheidung treffen, ob es noch sinnvoll ist, die Debug-Sitzung auszuführen, die Sie gerade starten wollten, oder sie abzubrechen und die Warnungen zuerst zu beheben.


3
Zum Guten oder zum Schlechten clippywarnt das Flusenwerkzeug für Rust tatsächlich vor der Konstante "3.14". Es ist eigentlich ein Beispiel in den Dokumenten . Aber wie Sie vielleicht aus dem Namen erraten können, ist er clippystolz darauf, aggressiv hilfreich zu sein.
Emk

1
@emk Danke für dieses Beispiel, vielleicht sollte ich meine Antwort so umformulieren, dass ich niemals "nie" sage . Ich wollte nicht sagen, dass das Überprüfen auf ungenaue π-Werte unmöglich ist, nur dass das bloße Entfernen von Warnungen keine anständige Codequalität garantiert.
Dmitry Grigoryev

Eine Warnung, die Sie aufgrund von Fehlern erhalten, ist, dass automatisierte Builds fehlschlagen und Sie darauf hinweisen, dass ein Fehler aufgetreten ist. Automatisierte Builds ermöglichen auch die Automatisierung von Flusen (Explosion ist 3 ... 2 ... 1 .. :)
Móż

8

Als jemand, der mit altem eingebettetem C-Code arbeitet, hat das Aktivieren von Compiler-Warnungen dazu beigetragen, viele Schwachstellen und Bereiche aufzuzeigen, die untersucht werden müssen, wenn Korrekturen vorgeschlagen werden. In gcc nutzen -Wallund -Wextraund sind sogar -Wshadowlebenswichtig geworden. Ich werde nicht jede einzelne Gefahr angehen, aber ich werde einige auflisten, die aufgetaucht sind und dazu beigetragen haben, Codeprobleme aufzuzeigen.

Variablen bleiben zurück

Dieser kann leicht auf unvollendete Arbeiten und Bereiche verweisen, in denen möglicherweise nicht alle übergebenen Variablen verwendet werden, was ein Problem sein könnte. Schauen wir uns eine einfache Funktion an, die dies auslösen kann:

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

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

Nur das Kompilieren ohne -Wall oder -Wextra gibt keine Probleme zurück. -Wand wird Ihnen sagen, obwohl das cnie verwendet wird:

foo.c: In der Funktion 'foo':

foo.c: 9: 20: Warnung: nicht verwendete Variable 'c' [-Wunused-Variable]

-Wextra sagt Ihnen auch, dass Ihr Parameter b nichts tut:

foo.c: In der Funktion 'foo':

foo.c: 9: 20: Warnung: nicht verwendete Variable 'c' [-Wunused-Variable]

foo.c: 7: 20: Warnung: nicht verwendeter Parameter 'b' [-Wunused-Parameter] int foo (int a, int b)

Globale variable Abschattung

Dieser ein bisschen schwer und zeigte sich nicht, bis -Wshadowverwendet wurde. Lassen Sie uns das obige Beispiel so ändern, dass es nur hinzugefügt wird, aber es gibt zufällig ein globales mit demselben Namen wie ein lokales, was bei dem Versuch, beide zu verwenden, viel Verwirrung stiftet.

int c = 7;

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

Wenn -Wshadow aktiviert war, ist dieses Problem leicht zu erkennen.

foo.c: 11: 9: Warnung: Deklaration von 'c' beschattet eine globale Deklaration [-Wshadow]

foo.c: 1: 5: Hinweis: Die schattierte Deklaration ist hier

Zeichenfolgen formatieren

Dies erfordert keine zusätzlichen Flags in gcc, war jedoch in der Vergangenheit immer noch die Ursache für Probleme. Eine einfache Funktion, die versucht, Daten zu drucken, aber einen Formatierungsfehler aufweist, könnte folgendermaßen aussehen:

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

Dadurch wird die Zeichenfolge nicht gedruckt, da das Formatierungsflag falsch ist und gcc Ihnen gerne mitteilt, dass dies wahrscheinlich nicht das ist, was Sie wollten:

foo.c: In der Funktion 'foo':

foo.c: 10: 12: Warnung: Format '% d' erwartet Argument vom Typ 'int', aber Argument 2 hat Typ 'const char *' [-Wformat =]


Dies sind nur drei der vielen Dinge, die der Compiler für Sie überprüfen kann. Es gibt viele andere, die gerne eine nicht initialisierte Variable verwenden, auf die andere hingewiesen haben.


7
In der eingebetteten Welt sind die Warnungen, die mich am meisten beunruhigen, " possible loss of precision" und " comparison between signed and unsigned" Warnungen. Ich finde es schwierig zu verstehen, wie viele "Programmierer" diese ignorieren (tatsächlich bin ich mir nicht sicher, warum sie keine Fehler sind)
Mawg sagt, Monica

3
Im letzteren Fall, @Mawg, glaube ich, dass der Hauptgrund dafür, dass es sich nicht um einen Fehler handelt, darin besteht, dass das Ergebnis von sizeofnicht signiert ist, sondern der Standard-Integer-Typ signiert ist. Der sizeofErgebnistyp size_twird normalerweise für alles verwendet, was mit der Typgröße zusammenhängt, z. B. Ausrichtung oder Anzahl der Array- / Containerelemente, während Ganzzahlen im Allgemeinen als " intsofern nicht anders erforderlich" verwendet werden sollen. Wenn man bedenkt, wie viele Leute auf diese Weise intlernen, ihre Container zu durchlaufen (im Vergleich intzu size_t), würde ein Fehler ungefähr alles kaputt machen. ; P
Justin Time - Wiedereinsetzung Monica

6

Dies ist eine spezifische Antwort auf C, und warum dies für C weitaus wichtiger ist als für alles andere.

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

Dieser Code wird mit einer Warnung kompiliert . Was in nahezu jeder anderen Sprache auf dem Planeten Fehler sind und sein sollten (mit Ausnahme der Assemblersprache), sind Warnungen in C. Warnungen in C sind fast immer Verkleidungsfehler. Warnungen sollten behoben und nicht unterdrückt werden.

Mit machen gccwir das als gcc -Wall -Werror.

Dies war auch der Grund für die hohe Unzufriedenheit mit einigen nicht sicheren MS-API-Warnungen. Die meisten Leute, die C programmieren, haben gelernt, Warnungen als Fehler zu behandeln, und dieses Zeug schien einfach nicht dasselbe zu sein und wollte nicht tragbare Korrekturen.


5

COMPILER-WARNHINWEISE SIND IHR FREUND (nicht schreien, zur Hervorhebung in Großbuchstaben).

Ich arbeite an älteren Fortran-77-Systemen. Der Compiler sagt mir wertvolle Dinge: Der Datentyp des Arguments stimmt bei einem Unterprogrammaufruf nicht überein. Dabei wird eine lokale Variable verwendet, bevor ein Wert in die Variable festgelegt wurde, wenn ich ein nicht verwendetes Variablen- oder Unterprogrammargument habe. Dies sind fast immer Fehler.

Vermeiden eines langen Beitrags: Wenn mein Code sauber kompiliert wird, funktioniert er zu 97%. Der andere Typ, mit dem ich arbeite, kompiliert mit allen Warnungen, verbringt Stunden oder Tage im Debugger und bittet mich dann um Hilfe. Ich kompiliere nur seinen Code mit den Warnungen und sage ihm, was zu beheben ist.


5

Sie sollten Compiler-Warnungen immer aktivieren, da der Compiler Ihnen häufig mitteilen kann, was mit Ihrem Code nicht stimmt. Dazu übergeben Sie -Wall -Wextraan den Compiler.

Sie sollten Warnungen normalerweise als Fehler behandeln, da die Warnungen normalerweise bedeuten, dass etwas mit Ihrem Code nicht stimmt. Es ist jedoch oft sehr einfach, diese Fehler zu ignorieren. Wenn Sie sie daher als Fehler behandeln, schlägt der Build fehl, sodass Sie die Fehler nicht ignorieren können. Um Warnungen als Fehler zu behandeln, übergeben Sie sie -Werroran den Compiler.


4

Die Compiler-Warnungen in C ++ sind aus bestimmten Gründen sehr nützlich.

1 - Es erlaubt Ihnen zu zeigen, wo Sie einen Fehler gemacht haben können, der das Endergebnis Ihrer Operationen beeinflussen kann. Zum Beispiel, wenn Sie keine Variable initialisiert haben oder wenn Sie "=" anstelle von "==" setzen (es gibt nur Beispiele)

2 - Es erlaubt Ihnen auch zu zeigen, wo Ihr Code nicht dem Standard von c ++ entspricht. Dies ist nützlich, da es einfach ist, den Code in eine andere Plattenform zu verschieben, wenn der Code dem tatsächlichen Standard entspricht.

Im Allgemeinen sind die Warnungen sehr nützlich, um Ihnen zu zeigen, wo Sie Fehler in Ihrem Code haben, die das Ergebnis Ihres Algorithmus beeinflussen oder Fehler verhindern können, wenn der Benutzer Ihr Programm verwendet.


4

Das Ignorieren von Warnungen bedeutet, dass Sie schlampigen Code hinterlassen haben, der nicht nur in Zukunft Probleme für andere verursachen kann, sondern auch dazu führt, dass wichtige Kompilierungsnachrichten von Ihnen weniger wahrgenommen werden. Je mehr Compiler ausgegeben werden, desto weniger wird jemand bemerken oder stören. Je sauberer desto besser. Es bedeutet auch, dass Sie wissen, was Sie tun. Warnungen sind sehr unprofessionell, nachlässig und riskant.


4

Ich habe einmal für eine große Firma (Fortune 50) gearbeitet, die elektronische Testgeräte herstellte.

Das Kernprodukt meiner Gruppe war ein MFC-Programm, das im Laufe der Jahre buchstäblich Hunderte von Warnungen generierte. Welche wurden in fast allen Fällen ignoriert.

Dies ist ein verdammter Albtraum, wenn Fehler auftreten.

Nach dieser Position hatte ich das Glück, als erster Entwickler in einem neuen Startup eingestellt zu werden.

Ich habe eine Richtlinie "Keine Warnung" für alle Builds empfohlen, bei der die Compiler-Warnstufen ziemlich laut sind.

Unsere Praxis bestand darin, #pragma warning - push / disable / pop für Code zu verwenden, von dem der Entwickler sicher war, dass er wirklich in Ordnung ist, zusammen mit einer Protokollanweisung auf Debug-Ebene, nur für den Fall.

Diese Praxis hat bei uns gut funktioniert.


1
Abgeordnet. #pragma warningunterdrückt nicht nur Warnungen, sondern dient dem doppelten Zweck, anderen Programmierern schnell mitzuteilen, dass etwas beabsichtigt und nicht zufällig ist, und dient als Such-Tag, um potenziell problematische Bereiche schnell zu lokalisieren, wenn etwas kaputt geht, die Fehler / Warnungen jedoch nicht repariere es.
Justin Time - Stellen Sie Monica

Du hast Recht, Justin, genau so habe ich die # Pragma-Warnung gesehen
Jim In Texas,

3

Eine Warnung ist ein Fehler, der darauf wartet, passiert zu werden. Sie müssen also Compiler-Warnungen aktivieren und Ihren Code aufräumen, um alle Warnungen zu entfernen.


3

Es gibt nur ein Problem bei der Behandlung von Warnungen als Fehler: Wenn Sie Code aus anderen Quellen verwenden (z. B. Micro $ ** t-Bibliotheken, Open Source-Projekte), haben sie ihre Arbeit nicht richtig gemacht, und das Kompilieren ihres Codes generiert Tonnen von Warnungen.

Ich immer meinen Code schreiben , so dass es keine Warnungen oder Fehler generiert, und reinigen Sie es , bis es kompiliert , ohne dass Nebengeräusche zu erzeugen. Der Müll, mit dem ich arbeiten muss, erschreckt mich und ich bin erstaunt, wenn ich ein großes Projekt erstellen und einen Strom von Warnungen beobachten muss, bei denen die Kompilierung nur ankündigen soll, welche Dateien sie verarbeitet hat.

Ich dokumentiere meinen Code auch, weil ich weiß, dass die tatsächlichen Lebenszeitkosten von Software hauptsächlich aus der Wartung stammen, nicht aus dem anfänglichen Schreiben, aber das ist eine andere Geschichte ...


Klopfen Sie nicht an, es gibt gutes Geld in der Beratung für Leute, die Compiler-Warnungen laut vorlesen können.
Móż

Code aus anderen Quellen Warnungen nicht zu erzeugen notwendig bedeuten , dass die Autoren waren schlampig. Dies kann auch bedeuten, dass sie den Code mit einem anderen Compiler kompiliert haben, der einen anderen Satz von Warnungen generiert hat. Code kann auf einem Compiler ohne Warnungen kompiliert und auf einem anderen Warnungen generiert werden. Oder vielleicht ist es nur eine andere Reihe von Warnoptionen; zB sie benutzt -Wallund du benutzt -Wall -Wextra.
Celtschk

2

Einige Warnungen können einen möglichen semantischen Fehler im Code oder eine mögliche UB bedeuten. ZB ;nach if(), nicht verwendete Variable, globale Variable, die durch lokale maskiert ist, oder Vergleich von vorzeichenbehafteten und vorzeichenlosen Variablen. Viele Warnungen beziehen sich auf den statischen Code-Analysator im Compiler oder auf Verstöße gegen den ISO-Standard, die zur Kompilierungszeit festgestellt werden können und "eine Diagnose erfordern". Während diese Vorkommnisse in einem bestimmten Fall legal sein können, sind sie meistens auf Designprobleme zurückzuführen.

Einige Compiler, z. B. gcc, haben eine Befehlszeilenoption, um den Modus "Warnungen als Fehler" zu aktivieren. Dies ist ein nettes, wenn auch grausames Werkzeug, um unerfahrene Programmierer auszubilden.


1

Die Tatsache , dass C ++ Compiler Code kompiliert accept dass offensichtlich Ergebnisse in undefiniertem Verhalten überhaupt ein großer Fehler in dem Compiler ist. Der Grund, warum sie dies nicht beheben, ist, dass dies wahrscheinlich einige verwendbare Builds beschädigen würde.

Die meisten Warnungen sollten schwerwiegende Fehler sein, die den Abschluss des Builds verhindern. Die Standardeinstellungen, nur Fehler anzuzeigen und den Build trotzdem auszuführen, sind falsch. Wenn Sie sie nicht überschreiben, um Warnungen als Fehler zu behandeln und einige Warnungen zu hinterlassen, wird Ihr Programm wahrscheinlich abstürzen und zufällige Dinge tun.


Ironischerweise verursacht eine Menge undefinierten Verhaltens keine Warnungen, sondern kompiliert sich lautlos zu einer bösen kleinen Zeitbombe. ; P
Justin Time - Wiedereinsetzung Monica

1
Das Problem ist, dass, wenn der Standard eine Fehlermeldung verlangt, diese Fehlermeldung in allen Fällen ausgegeben werden muss, in denen das Problem auftritt, jedoch niemals, wenn das Problem nicht auftritt. In Fällen wie undefiniertem Verhalten kann dies jedoch unmöglich zu entscheiden sein. Betrachten wir zum Beispiel den folgenden Code: int i; if (fun1()) i=2; if (fun2()) i=3; char s="abcde"[i];Dieser Code zeigt nicht definiertes Verhalten , wenn und nur wenn beide fun1()und fun2()zurückgeben können falseauf dem gleichen Funktionsausführung. Was mag wahr sein oder nicht, aber wie soll der Compiler das sagen?
Celtschk

-2

Sie sollten auf jeden Fall Compiler-Warnungen aktivieren, da einige Compiler einige häufige Programmierfehler nicht melden können, darunter die folgenden: -

-> eine Variable initialisieren wird vergessen -> einen Wert von einer Funktion zurückgeben wird übersehen -> die einfachen Argumente in printf- und scanf-Familien, die nicht mit der Formatzeichenfolge übereinstimmen, die eine Funktion verwendet, ohne vorher deklariert zu werden, obwohl dies nur in c vorkommt

Da diese Funktionen erkannt und gemeldet werden können, ist dies normalerweise nicht standardmäßig der Fall. Daher muss diese Funktion explizit über Compileroptionen angefordert werden.


-32

Nehmen Sie es ruhig: Sie müssen nicht, es ist nicht notwendig. -Wall and -Werror wurde von Code-Refactoring-Maniacs für sich selbst entwickelt: Es wurde von Compiler-Entwicklern erfunden, um zu vermeiden, dass vorhandene Builds nach Compiler-Updates auf der Benutzerseite beschädigt werden . Die Funktion ist nichts, aber alles über die Entscheidung, den Build zu brechen oder nicht zu brechen.

Es liegt ganz bei Ihnen, ob Sie es verwenden oder nicht. Ich benutze es die ganze Zeit, weil es mir hilft, meine Fehler zu beheben.


19
Obwohl es nicht obligatorisch ist , wird dringend empfohlen , sie zu verwenden
Spikatrix

18
-Wall and -Werror was designed by code-refactoring maniacs for themselves.[Zitat benötigt]
YSC

22
Es scheint, als ob Sie sich selbst widersprechen. Wenn Sie es "die ganze Zeit verwenden, weil es hilft, [Ihre] Fehler zu beheben", lohnt es sich nicht, neueren Programmierern beizubringen, damit sie es von Anfang an überall tun? Ich glaube nicht, dass diese Frage die Frage stellt, ob es möglich ist , ohne zu kompilieren, -Wallund -Werrorsie fragt nur, ob es eine gute Idee ist. Was aus Ihrem letzten Satz so klingt, als würden Sie sagen, dass es so ist.
scohe001

12
Wenn Sie mehr Erfahrung mit der Pflege von Code haben, der nicht von Ihnen geschrieben wurde, wiederholen Sie diese Antwort.
Thorbjørn Ravn Andersen

Dies ist keine hilfreiche Antwort. Die OP-Frage enthält 4 Fragezeichen. Wie viele Antworten beantwortet diese Antwort?
Anders
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.