Warum wird dieser C-Code kompiliert?

Lesezeit: 3 Minuten
#include <stdio.h>
int main() {
    int c = c;
    printf("c is %i\n", c);
    return 0;
}

Ich definiere eine ganzzahlige Variable namens c, und ich weise seinen Wert sich selbst zu. Aber wie kann man das überhaupt kompilieren? c wurde nicht initialisiert, wie kann also sein Wert sich selbst zugewiesen werden? Wenn ich das Programm starte, bekomme ich c is 0.

Ich gehe davon aus, dass der Compiler Assembler-Code generiert, der Platz für die zuweist c Variable (wenn der Compiler auf die int c Aussage). Dann nimmt es den Junk-Wert, der sich in diesem nicht initialisierten Bereich befindet, und weist ihn wieder zu c. Ist das was passiert?

  • Leider ist es erlaubt – Sie können den Compiler normalerweise dazu bringen, eine Warnung darüber auszugeben, zum Beispiel wenn Sie g++ (aber aus irgendeinem Grund nicht gcc) verwenden, indem Sie das -Wall-Flag verwenden, um eine Warnung zu erzeugen.

    anon

    13. Juli 2010 um 16:51 Uhr

  • @Neil, um einen Fehler mit gcc zu erzwingen, verwenden Sie -Werror=uninitialized -Winit-self

    – Matthäus Flaschen

    13. Juli 2010 um 17:01 Uhr

Benutzer-Avatar
Brian R. Bondy

Ich erinnere mich, dass ich dies in einer früheren Antwort zitiert habe, aber ich kann es im Moment nicht finden.

C++03 §3.3.1/1:

Der Deklarationspunkt für einen Namen liegt unmittelbar nach seinem vollständigen Deklarator (Klausel 8) und vor seinem Initialisierer (falls vorhanden), …

Daher ist die Variable c bereits vor dem Initialisierungsteil verwendbar.

Bearbeiten: Entschuldigung, Sie haben speziell nach C gefragt; obwohl ich sicher bin, dass es dort eine gleichwertige Zeile gibt. James McNellis hat es gefunden:

C99 §6.2.1/7: Jeder Bezeichner, der kein Struktur-, Vereinigungs- oder Aufzählungs-Tag ist, „hat einen Geltungsbereich, der direkt nach der Vervollständigung seines Deklarators beginnt.“ Auf den Deklarator folgt der Initialisierer.

  • Vielen Dank! Hervorragende Erklärung!

    – Vivin Paliath

    13. Juli 2010 um 17:02 Uhr

  • C99 §6.2.1/7: Jeder Bezeichner, der kein Struktur-, Vereinigungs- oder Aufzählungs-Tag ist, „hat einen Geltungsbereich, der direkt nach der Vervollständigung seines Deklarators beginnt.“ Auf den Deklarator folgt der Initialisierer.

    – James McNellis

    13. Juli 2010 um 17:48 Uhr


Deine Vermutung ist genau richtig. int c verschiebt Platz auf dem Stack für die Variable, die dann gelesen und für die neu geschrieben wird c = c Teil (obwohl der Compiler das optimieren kann). Ihr Compiler überträgt den Wert auf as 0aber das ist nicht garantiert immer der Fall.

  • Es wird wahrscheinlich nicht 0 gedrückt, es ist nur so, dass der vorhandene Stapelrahmen bereits 0 Speicher enthält. Abhängig davon, ob 0 vorhanden ist, ist natürlich undefiniert.

    – Jan Ramin

    13. Juli 2010 um 16:57 Uhr

  • Viel bessere Antwort als aus dem Standard zu zitieren.

    – kirk.burleson

    13. Juli 2010 um 18:13 Uhr

  • @kirk Viele Leute bevorzugen einen Verweis auf den Standard, damit Sie wissen, dass es sich um ein garantiertes Verhalten handelt und nicht nur um eine Konvention oder einen Zufall

    – Michael Mrozek

    15. Juli 2010 um 6:35 Uhr

  • @Michael – Und viele Leute bevorzugen eine einfache Erklärung.

    – kirk.burleson

    15. Juli 2010 um 12:43 Uhr

  • Ich kann nicht sagen, dass ich den Satz mag “schiebt Leerzeichen auf den Stack”. Es ist als solches nicht falsch, aber … vielleicht “reserviert Platz auf dem Stack” oder “stellt sicher, dass Platz auf dem Stack vorhanden ist”.

    – dmckee — Ex-Moderator-Kätzchen

    15. Juli 2010 um 17:22 Uhr

Benutzer-Avatar
Matthäus Flaschen

Es ist ein undefiniertes Verhalten, einen nicht initialisierten Wert zu verwenden (§C99 J.2 „Der Wert eines Objekts mit automatischer Speicherdauer wird verwendet, solange er unbestimmt ist“). Da kann also alles passieren nasale Dämonen zu c = 0, zu Nethack spielen.

  • Der Wert ist unbestimmt, aber das ist kein undefiniertes Verhalten. Nasendämonen und Nethack sind draußen. c = 0 ist möglich (und wahrscheinlich). Das Verhalten ist hier ähnlich wie bei einem Zufallszahlengenerator definiert, indem wir zwar den resultierenden Wert nicht bestimmen können, uns aber durch den Standard garantiert werden kann, dass der Wert das einzige Unbekannte an dieser Aussage ist.

    – Michael Gazonda

    11. Juli 2014 um 18:37 Uhr


c wurde initialisiert!

Obwohl dies eine Codezeile ist, initialisiert sie tatsächlich zuerst c und weist ihr dann c zu. Sie haben einfach Glück, dass der Compiler c für Sie auf Null initialisiert.

Die C-Spezifikation garantiert nicht, dass Variablen mit 0, 0.0 oder “” oder ” initialisiert werden.

Das ist ein Besonderheit von Compilern und niemals müssen Sie drängen, dass das passieren wird.

Ich stelle meinen IDE/Compiler immer so ein, dass er davor warnt.

1284060cookie-checkWarum wird dieser C-Code kompiliert?

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

Privacy policy