Frage g ++ Compiler: Optimierungsflag fügt eine Warnmeldung hinzu


Ich bemerkte dieses interessante Verhalten des g ++ Compilers, wenn ich dem Compiler ein -O3-Flag hinzufüge, bekomme ich

otsu.cpp:220: warning: ‘x’ may be used uninitialized in this function

Wenn ich jedoch keine Optimierung verwende und stattdessen ein Debug-Flag -g verwende, habe ich überhaupt keine Warnungen erhalten. Jetzt vertraue ich dem Compiler mehr, wenn das Flag -g eingeschaltet ist; Ich frage mich jedoch, ob dies wohldefiniertes Verhalten ist, das erwartet werden sollte?

Zur Verdeutlichung ist der Code, der dies verursacht, in etwa so:

int x; //uninitialized


getAValueForX( &x ); // function makes use of x,
                     // but x is unitialized

woher

 void getAValueForX( int *x )
 {
     *x = 4;
 }

oder etwas in dieser Richtung, offensichtlich komplexer.


6
2018-01-26 20:18


Ursprung


Antworten:


Das ist zu erwarten. Die Optimierungen bewirken, dass eine bestimmte Codeanalyse ausgeführt wird und gcc findet die nicht initialisierten Variablen. Es ist in der Handbuchseite:

. . . Diese Warnungen hängen von der Optimierung ab

http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html


16
2018-01-26 20:24



Dies ist bei gcc sehr häufig. Und ja, das ist zu erwarten.

Soweit ich verstanden habe, generiert der Compiler zur Optimierung viele Metriken und transformiert den Code (oder, genauer gesagt, die Repräsentation, die er vom Code hat) in einer Weise, die die Erkennung von nicht initialisierten oder nicht verwendeten Variablen für Beispiele erlaubt (Es gibt ein paar andere Warnungen wie diese, ich erinnere mich nicht an die Liste).

Würde man dasselbe ohne Optimierung tun, müsste man dies tun und dann diese ganze Analyse verwerfen. Dies würde die Kompilierung für keinen guten Zweck erheblich verlangsamen (zumal der Compiler beim Debuggen den Code nicht neu anordnen soll).


3
2018-01-26 20:24



Die Code-Flow-Analyse, die der Optimierer ausführt, ermöglicht es, potenzielle Probleme zu erkennen, die normale (und schnellere) Kompilierung nicht erkennen kann. Das Problem war immer da, der Compiler hat es einfach nicht überprüft.

Selbst wenn diese Warnung ausgegeben wird, kann es tatsächlich kein Problem aufgrund der tatsächlichen Verwendung der Funktion in der Praxis sein; Der Compiler wird davon ausgehen, dass alle möglichen Werte der Typen seiner Argumente (und alle externen Variablen, die innerhalb der Funktion verwendet werden) in allen möglichen Kombinationen auftreten können - was zu mindestens einem Pfad führt, in dem die Variable verwendet wird, ohne einen Wert zugewiesen zu bekommen. Ihre tatsächliche Verwendung wird einen viel restriktiveren Satz möglicher Zustände haben, so dass der Pfad in der Praxis niemals vorkommen kann. Die einfache Lösung besteht lediglich darin, die Variable zu initialisieren, nur um den Compiler zu schließen - es kostet Sie nichts.

Ich benutze den Optimierer immer als eine Form der statischen Analyse des armen Mannes, auch wenn ich nicht beabsichtige, ihn im Produktionscode zu verwenden. Gleichermaßen verwende ich oft mehr als einen Compiler aus dem gleichen Grund. Einige Compiler führen Prüfungen durch, die andere nicht durchführen, oder sie erzeugen unterschiedlich formulierte Nachrichten für die gleichen Fehler, was oft bei ihrer Interpretation für einige der stumpferen Nachrichten hilft.

Zitat:

Ich vertraue dem Compiler mehr, wenn das -g   Flagge ist an

Es stimmt zwar, dass ein Compiler mit einem Fehler wahrscheinlich im Optimierer liegt (es ist der komplexeste Teil), aber für einen ausgereiften Compiler wie GCC wäre dies ein sehr seltener Fund. Umgekehrt finden Leute oft, dass ihr Arbeitscode bei der Optimierung versagt; Meistens war der Code immer fehlerhaft (vielleicht beruhte er auf undefiniertem oder compilerdefiniertem Verhalten), und der Optimierer hat gerade diesen Fehler aufgedeckt. Also ich schlage vor, wenn Sie Ihren Code unter Optimierung zu finden, den Code vor dem Compiler verdächtigen - Ockhams Razor gilt.


3
2018-01-26 23:03



Meine Compiler-Flags:

CFLAGS=-W -Wall\
 -Wno-non-template-friend\
 -Wold-style-cast\
 -Wsign-promo\
 -Wstrict-null-sentinel\
 -Woverloaded-virtual
# -Weffc++

-Weffc ++ kann sehr nervig sein, also versuche ich es manchmal, aber generell halte ich es ausgeschaltet. Probieren Sie diese - und andere im Handbuch - und lassen Sie uns sehen, was wir sehen.


1
2018-01-26 20:24



Ja, das ist wohldefiniertes Verhalten. Wenn der Optimierer von GCC nicht aktiviert ist, führt er bestimmte Arten der Ausführungspfadprüfung nicht aus (um die Leistungseinbußen bei solchen Überprüfungen zu vermeiden). Bestimmte Situationen, wie die Verwendung nicht initialisierter Variablen, können nur erkannt werden, wenn diese zusätzlichen Prüfungen durchgeführt werden. Daher mit -O0, GCC kann nicht über diese Bedingungen warnen.


1
2018-01-26 20:26



Nun, die Tatsache, dass der Compiler Dinge zur Optimierung bewegen kann, kann zu Problemen führen und zu undefiniertem Verhalten führen (wie in den manuellen Zuständen unten angegeben); Ich denke, es wäre hilfreich, den Code zu sehen, der versucht, Sinn zu machen.

Die Verknüpfungen, die von optimiertem Code verwendet werden   kann gelegentlich überraschend erzeugen   Ergebnisse: einige Variablen, die Sie deklariert haben   mag überhaupt nicht existieren; Ablauf der Kontrolle   kann sich kurz bewegen, wo Sie nicht waren   erwarte es; einige Aussagen dürfen nicht sein   ausgeführt, weil sie Konstante berechnen   Ergebnisse oder ihre Werte waren bereits   verfügbar; Einige Anweisungen können ausgeführt werden   an verschiedenen Orten, weil sie es waren   ausgezogen aus Loops.


1
2018-01-26 20:26



Ich habe das gleiche Problem in meinem msvc 6 Compiler. Durch das Initialisieren der fraglichen Variablen wird die Möglichkeit eines fehlerhaften Pfades aus der Sicht des Compilers entfernt.


0
2018-01-27 00:29