Wie kann ich gcc dazu bringen, mich vor “int i = i;” zu warnen?

Lesezeit: 5 Minuten

Benutzer-Avatar
nichtnichtunsichtbar

Ein einfaches Programm:

int main()
{
    long i = i;

    return 0;
}

Kompilieren als C gibt keine Fehler und keine Warnungen.

$ gcc -Wall -Wextra -pedantic 1.c

Das Kompilieren als C++ gibt eine Warnung aus:

$ c++ -Wall -Wextra -pedantic 1.c
1.c: In function ‘int main()’:
1.c:3:7: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
  long i = i;

In beiden Fällen scheint die Variable i 0 zu sein, obwohl sie in c++ nicht initialisiert sein könnte. Ich habe tatsächlich einen solchen Tippfehler in einer meiner Funktionen gemacht und es war ziemlich schwer, ihn zu finden. Was kann ich tun, um dies zu vermeiden? Ich würde mindestens eine Warnung erwarten. Außerdem gibt Clang in beiden Fällen (c oder c++) keine Warnung aus. Gibt es einen bestimmten Teil des Standards, der etwas über dieses Verhalten aussagt?

Edit: etwas ähnliches probiert:

$ cat 1.c
int main(void)
{
    int k = k + 0;
    int i = i + 1;
    return 0;
}

Die Warnung (in C) wird nur für “i” generiert.

$ gcc -Wall -Wextra 1.c
1.c: In function ‘main’:
1.c:4:6: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
  int i = i + 1;

  • C ist im Allgemeinen mit Trash-Werten einverstanden, aber das ist irgendwie überraschend, besonders nachdem ich so lange mit Python gearbeitet habe (ich erwarte einen NameError :)).

    – Verrückter Physiker

    25. September 2018 um 13:05 Uhr

  • Warnungen sind ein Problem der “Qualität der Implementierung”. Die Norm sagt nichts darüber aus.

    – Basile Starynkevitch

    25. September 2018 um 13:07 Uhr

  • @KABoissonneault, es ist immer noch ein undefiniertes Verhalten in C. Da nicht initialisierte Variablen in C Mülldaten haben, ist es unvorhersehbar, was bei einer solchen Operation resultieren wird, oder sogar wenn diese Variable in der RHS einer Anweisung verwendet wird.

    – absolutWassermann

    25. September 2018 um 13:13 Uhr

  • Es wird kompiliert, weil die Regeln von C & C++ einfach nicht streng genug oder gut genug sind. Nicht-alte Sprachen erlauben solche Konstrukte nicht.

    – Boanne

    25. September 2018 um 13:14 Uhr


  • “unvorhersehbare Daten” ist eine Form von nicht spezifiziertem Verhalten. Undefiniertes Verhalten bedeutet, dass es absolut keine Einschränkungen gibt, was die Implementierung tun kann

    – KABoissonneault

    25. September 2018 um 13:15 Uhr

Benutzer-Avatar
rici

Für GCC, das C-Programme kompiliert, müssen Sie das Compiler-Flag hinzufügen -Winit-self. (Du brauchst ausserdem -Wall oder -Wuninitializedsiehe unten.) Für GCC, die C++-Programme kompilieren, wird dieses Flag durch impliziert -Wall aber für C muss es explizit angegeben werden; es ist nicht Teil von -Wextra entweder.

Für Clang ist die Situation etwas interessanter. Im Snippet im OP erzeugt Clang keine Diagnose. Mit dem etwas anderen Snippet im GCC-Handbuch unten wird jedoch eine Diagnose bereitgestellt:

int f() {
  int i = i;
  return i;
}

Der Unterschied besteht darin, dass im obigen Ausschnitt der (nicht initialisierte) Wert von i wird tatsächlich verwendet. Anscheinend hat Clang im ursprünglichen Code festgestellt, dass die Variable nutzlos war, und sie als toten Code eliminiert, bevor die Diagnose angewendet wurde.

In Clang wird die Diagnose durch ausgelöst -Wuninitializeddie durch aktiviert wird -Wall wie im GCC.


Hier ein Auszug aus dem GCC-Handbuch:

-Winit-self (nur C, C++, Objective-C und Objective-C++)

Warnt vor nicht initialisierten Variablen, die mit sich selbst initialisiert werden. Beachten Sie, dass diese Option nur mit verwendet werden kann -Wuninitialized Möglichkeit.

GCC warnt beispielsweise davor i wird im folgenden Ausschnitt nur dann nicht initialisiert, wenn -Winit-self wurde angegeben:

        int f()
          {
            int i = i;
            return i;
          }

Diese Warnung wird aktiviert durch -Wall in C++.

Wie der Auszug zeigt, -Wuninitialized ist ebenfalls erforderlich. Sowohl in C als auch in C++ -Wall impliziert -Wuninitialized. Beachten Sie jedoch, dass viele nicht initialisierte Verwendungen nicht erkannt werden, es sei denn, es wird auch eine gewisse Optimierungsstufe angefordert. (Das trifft nicht zu -Winit-self, Soweit ich weiss. Es kann ohne Optimierung erkannt werden.)


Irritierenderweise verschwinden die zuvor markierten Duplikate, wenn Sie die Markierung einer Frage als Duplikat aufheben. Ich habe die Markierung aufgehoben, weil keines der Duplikate tatsächlich die Frage im Text beantwortet hat; Ich habe auch den Titel angepasst.

Als Referenz sind hier die Originalduplikate, die von Interesse sein könnten:

  • Warum erlaubt der Compiler, eine Variable mit sich selbst zu initialisieren?

  • gcc warnt nicht vor nicht initialisierter Variable

  • Warum wird diese Initialisierung vom C++-Compiler akzeptiert? statische Ganzzahl x = x;

  • Hat sich der C++-Standard in Bezug auf die Verwendung von unbestimmten Werten und undefiniertem Verhalten in C++14 geändert?

  • Was ist der Sinn einer Warnung, die Sie selbst herausfinden müssen, bevor Sie eine Compiler-Option verwenden? Die Jungs von gcc machen es manchmal etwas knifflig!!! 🙂

    – Luis Colorado

    27. September 2018 um 8:51 Uhr

Benutzer-Avatar
Samini

Es ist im Grunde:

int i;
i = i;

in welchem i ist ein nicht initialisierter Wert.

  • @notnonuninvisible – C und C++ sind keine “sicheren Sprachen” und waren es nie. Es macht wenig Sinn, einen Compiler zu verzerren, um ihn gegen jeden denkbaren menschlichen Fehler zu schützen. Das ist der ganze Grund, warum UB in diesen Sprachen eine Sache ist.

    – StoryTeller – Unslander Monica

    25. September 2018 um 13:25 Uhr

  • wie beantwortet das die frage? Es gibt eine Warnung in der Art von “Variable i darf nicht initialisiert verwendet werden”, und der Compiler könnte diese Warnung anzeigen

    – 463035818_ist_keine_Nummer

    25. September 2018 um 13:30 Uhr

  • @notnonuninvisible – Ich habe nicht “schlecht” gesagt. Ich sagte “nicht sicher”. Es ist nicht ein und dasselbe. Auch fehlende Sicherheit ist Macht, denn nichts belastet Sie mit Sicherheitsnetzen, die Sie nicht brauchen. Und es tut mir leid, aber die Diskussion dieses philosophischen Punkts ist nicht zum Thema. Der einzige zum Thema gehörende Punkt, ob es erlaubt ist, wird im Dupe beantwortet, den ich meiner Meinung nach treffend gewählt habe.

    – StoryTeller – Unslander Monica

    25. September 2018 um 13:33 Uhr


  • Diese Diskussion geht am Thema vorbei. Es soll in einem Chatraum fortgesetzt werden.

    – Francois Andrieux

    25. September 2018 um 13:54 Uhr

  • Diese Antwort scheint die Frage nicht zu beantworten, die lautet: “Wie kann ich gcc dazu bringen, mich vor ‘int i=i;’ zu warnen?”

    – Jeremy Friesner

    25. September 2018 um 14:59 Uhr

Die Kombination von -Wall -Winit-self scheint diese Diagnose hinzuzufügen:

$ gcc -Wall      -Winit-self t.c
t.c: In function ‘main’:
t.c:3:10: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
     long i = i;
          ^

  • Insbesondere wird es aktiviert durch -Wuninitialized -Winit-self (Ersteres wird ermöglicht durch -Wall)

    – Jonathan Wakely

    25. September 2018 um 16:09 Uhr

1367050cookie-checkWie kann ich gcc dazu bringen, mich vor “int i = i;” zu warnen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy