Warum gibt der Compiler diese Warnung aus: "fehlender Initialisierer"? Ist die Struktur nicht initialisiert?

79

Ich erstelle eine Art Frontend für ein Programm. Zum Starten des Programms verwende ich den Aufruf CreateProcess(), der unter anderem einen Zeiger auf eine STARTUPINFOStruktur erhält . Um die Struktur zu initialisieren, die ich früher gemacht habe:

Wenn -Wall -Wextraich das Programm mit GCC kompiliere, das diese Warnsätze aktiviert , erhalte ich eine Warnung, dass ein Initialisierer fehlt, der auf die erste Zeile zeigt.

Also habe ich Folgendes gemacht:

Auf diese Weise gibt der Compiler keine Warnung aus. Die Frage ist, was ist der Unterschied zwischen diesen Arten der Initialisierung einer Struktur? Wird die Struktur mit der ersten Methode nicht initialisiert? Welches würdest du empfehlen?

Shantia
quelle
1
Die Warnung ist genau das: eine Warnung. Es ist in Ordnung, diese spezielle Warnung bei dieser speziellen Gelegenheit zu ignorieren. Der Compiler gibt die Warnung aus, um Ihnen in folgenden Fällen zu helfen: struct struct_with_four_fields x = {1, 2, 3};Wenn nur 3 von 4 Mitgliedern initialisiert werden.
pmg
In meinem vorherigen Kommentar wurde das 4. Mitglied auf 0 initialisiert.
pmg
5
Die Warnung vor fehlenden Initialisierern ist im Allgemeinen nicht unangemessen. Wenn Sie eine Struktur mit 4 Mitgliedern haben und nur für 3 Initialisierer bereitstellen, ist dies wahrscheinlich ein Fehler. Dies { 0 }ist jedoch eine gebräuchliche und genau definierte Redewendung zum Initialisieren aller Mitglieder auf Null (rekursiv für jedes Untermitglied definiert). Aus diesem Grund wurden spätere Versionen von gcc geändert, um nicht vor diesem speziellen Fall zu warnen.
Keith Thompson
@ KeithThompson wovon redest du? Ich benutze gcc 4.8.2 und seit der Frage sind fünf Jahre vergangen. PS: Es gab noch eine Mail, die ich am Ende verlinken wollte, aber zu meinem Wunder fehlt sie. Wahrscheinlich speichert der Mailserver nicht alle Nachrichten, das ist traurig, die Mail wäre für jemanden nützlich, der das Problem erneut löst.
Hi-Angel
4
@ Hi-Angel: Wenn ich ein kleines Programm mit gcc-4.8.1 unter Solaris kompiliere, erhalte ich die Warnung "Warnung: fehlender Initialisierer". Wenn ich dasselbe Programm mit gcc-4.8.2 unter Linux Mint kompiliere, wird keine Warnung angezeigt. Im Übrigen ist die Zeile obj = {0};in der Nachricht, mit der Sie verknüpft haben, ungültig C, und gcc 4.8.2 weist sie als Syntaxfehler zurück. Wenn Sie als C ++ kompilieren, denken Sie daran, dass es sich um eine andere Sprache handelt und gcc ein anderes Frontend verwendet. Korrekturen im C-Compiler von gcc können für g ++ gelten oder nicht.
Keith Thompson

Antworten:

87

GCC ist einfach zu paranoid - meiner Meinung nach ohne guten Grund, aber dann ist es sicher richtig, dass die GCC-Betreuer viel mehr über die Nuancen von C wissen, die ich tue.

Siehe diesen kleinen Diskussionsthread über das Problem auf der GCC-Mailingliste:

Fazit: Wenn Sie die Struktur mit just {0}initialisieren, wird das Ganze tatsächlich mit Null initialisiert.

Der C99-Standard besagt in 6.7.8 / 21 "Initialisierung - Sematik" Folgendes:

Wenn eine in Klammern eingeschlossene Liste weniger Initialisierer enthält als Elemente oder Elemente eines Aggregats oder weniger Zeichen in einem Zeichenfolgenliteral, das zum Initialisieren eines Arrays bekannter Größe verwendet wird, als Elemente im Array vorhanden sind, muss der Rest des Aggregats implizit wie Objekte mit statischer Speicherdauer initialisiert werden.

C90 sagt im Wesentlichen dasselbe in 6.5.7 mit einem etwas anderen Wortlaut (mit anderen Worten, C99 hat hier nichts Neues hinzugefügt).

Beachten Sie auch, dass dies in C ++ so erweitert wurde, dass ein leerer Satz von Klammern " {}" eine Wertinitialisierung für ein Objekt durchführt, da es Situationen (wie Vorlagen) gab, in denen Sie nicht einmal wussten, welche Mitglieder oder wie viele Mitglieder ein Typ sind könnte haben. Es ist also nicht nur eine gute Praxis, sondern manchmal auch erforderlich, eine Initialisierungsliste zu haben, die kürzer ist als die Anzahl der Mitglieder, die ein Objekt möglicherweise hat.

Michael Burr
quelle
19
Ich musste hinzufügen -Wno-missing-field-initializersund -Wno-missing-bracesso hörte GGC auf zu stöhnen, dass ich = {0};meine Strukturen einsetzte. Weiß jemand, ob beim Deaktivieren dieser Warnung Warnungen für andere Dinge als = {0};für Strukturen übersehen werden?
Matt Clarkson
4
Der Fix ist in gcc 4.7.0 vorhanden , nicht jedoch in gcc 4.6.3 .
Spleißer
1
@splicer: Welches "the" Update? Außerdem kompiliere mingw32-g++.exe (GCC) 4.7.2ich diese Warnung und erhalte sie in der obigen Sprache (sogar im genauen Fall von STARTUPINFO).
Jan Hudec
2
@ Jan Hudec: Revision 172857 . Leider funktionieren die URLs aus meinen vorherigen Kommentaren nicht mehr. Hier ist der Fehler, der mit dem Fix verbunden ist: gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
Splicer
9
Ich erhalte auch mit gcc 4.9.3 immer noch die Warnung, wenn ich die leere Klammer {}oder {0}Initialisierer in meinen C ++ - Klassen verwende: /
Kamil Kisiel
21

Dies kann für GCC in C ++ - Programmen leicht behoben werden, indem die Struktur als initialisiert wird

  • habe genau das vor ein paar Tagen getan
dmityugov
quelle
1
Eine mögliche Gefahr bei dieser Antwort besteht darin, dass in C ++ 98 die Felder nicht auf Null initialisiert wurden. Das Nullinitialisierungsverhalten wurde in C ++ 03 hinzugefügt.
MM
1
@MM Vielen Dank, dass Sie auf die mögliche Gefahr hingewiesen haben, aber ich denke, im Dezember 2018 sollte dies keine gefährliche Situation mehr im Code sein. Übrigens finde ich diese Antwort am besten!
Peter VARGA
@AlBundy Leider gibt es immer noch einige Compiler, die die C ++ 98-Initialisierung verwenden (z. B. den 32-Bit-Modus C ++ Builder XE5, den ich gerade zufällig geöffnet habe)
MM
Aus diesem Grund musste ich meiner Datei mehr als 10 Codezeilen hinzufügen. Ich bin wirklich wütend Es wurde versucht, anonyme Objekte in einem Funktionsaufruf zu übergeben. Wenn ich {} oder {0} verwendet habe, wurde diese Warnung angezeigt (als Fehler behandelt). Wenn ich () verwendet habe, dann denkt gcc, dass es ein Funktionsaufruf ist ...
bencemeszaros
15

Sie haben so viele Warnungen wie möglich angefordert -Wall -Wextra.

In diesem Fall erhalten Sie eine Warnung, die Sie darüber informiert, dass Sie nicht alle Felder angegeben haben. Dies ist vollkommen gültig, könnte aber unbeabsichtigt gewesen sein.

Sie können diese Warnung durch Hinzufügen unterdrücken -Wno-missing-field-initializers

Ökotax
quelle
12

Auf dieser Webseite wird das zugrunde liegende Problem ausführlich erläutert: http://ex-parrot.com/~chris/random/initialise.html

Als Workaround besteht meine aktuelle Lösung darin, diese Warnung selektiv zu unterdrücken:

Leider funktioniert dies nur in Clang und scheint in GCC nicht zu funktionieren.

JanX2
quelle
4
Ich kann bestätigen: #pragma GCC diagnostic ignored "-Wmissing-field-initializers"vom GCC-Compiler 4.2.1 akzeptiert, aber nichts tun. unsicher über neue Versionen von gcc
Maxim Kholyavkin
1
@speakus, ich kann bestätigen, dass es mit dem neuesten (zum Zeitpunkt des Schreibens) gcc (7.3.0) funktioniert.
Cydef
@cydef Laut anderen Kommentaren und den Fehlerberichten, die ich gesehen habe, warnt GCC (ab GCC 5) überhaupt nicht mehr davor - unabhängig davon #pragma clang diagnostic ignored "-Wmissing-field-initializers". Sie sollten wahrscheinlich prüfen, ob dies der Fall ist.
WD40
1

In C ++ können Sie boost::initialized_valuediese Warnung entfernen. Ich habe Warnungen deaktiviert für boost; Ich weiß also nicht, ob dies in Ihrem Fall zu anderen Warnungen führen würde. Auf diese Weise müssen Sie die Warnung nicht deaktivieren.

Beispiel:

Michael F. Hancock
quelle