Was passiert, wenn eine Variable den Gültigkeitsbereich verlässt?

Lesezeit: 3 Minuten

In den meisten verwalteten Sprachen (also solchen mit GC) sind lokale Variablen, die den Gültigkeitsbereich verlassen, nicht zugänglich und haben eine höhere GC-Priorität (daher werden sie zuerst freigegeben).

Nun, C ist keine verwaltete Sprache, was passiert mit Variablen, die hier den Gültigkeitsbereich verlassen?

Ich habe einen kleinen Testfall in C erstellt:

#include <stdio.h>
int main(void){
    int *ptr;

    {
        // New scope
        int tmp = 17;
        ptr = &tmp; // Just to see if the memory is cleared
    }

    //printf("tmp = %d", tmp); // Compile-time error (as expected)
    printf("ptr = %d\n", *ptr);

    return 0;
}

Ich verwende GCC 4.7.3 zum Kompilieren und das obige Programm wird gedruckt 17, Warum? Und wann/unter welchen Umständen werden die lokalen Variablen freigegeben?

  • gcc 4.7.3 wurde bis heute nicht veröffentlicht. Das muss ein sein 4.7.3 Vorabveröffentlichung.

    – au

    15. Dezember 2012 um 1:07 Uhr

AnT steht mit Russlands Benutzer-Avatar
AnT steht zu Russland

Das tatsächliche Verhalten Ihres Codebeispiels wird durch zwei Hauptfaktoren bestimmt: 1) das Verhalten ist nicht definiert durch die Sprache, 2) ein optimierender Compiler generiert Maschinencode, der physikalisch nicht mit Ihrem C-Code übereinstimmt.

Trotz der Tatsache, dass das Verhalten undefiniert ist, kann (und wird) GCC Ihren Code beispielsweise leicht zu einem reinen optimieren

printf("ptr = %d\n", 17);

was bedeutet, dass die Ausgabe, die Sie sehen, sehr wenig damit zu tun hat, was mit irgendwelchen Variablen in Ihrem Code passiert.

Wenn Sie möchten, dass das Verhalten Ihres Codes besser widerspiegelt, was physikalisch passiert, sollten Sie Ihre Zeiger deklarieren volatile. Das Verhalten wird immer noch undefiniert sein, aber es wird zumindest einige Optimierungen einschränken.

Nun zu dem, was mit lokalen Variablen passiert, wenn sie den Gültigkeitsbereich verlassen. Es passiert nichts Physisches. Eine typische Implementierung weist genügend Platz im Programmstapel zu, um alle Variablen auf der tiefsten Ebene der Blockverschachtelung in der aktuellen Funktion zu speichern. Dieser Speicherplatz wird normalerweise beim Funktionsstart auf einmal im Stack zugewiesen und beim Funktionsausgang wieder freigegeben.

Das bedeutet, dass der Speicher früher von belegt ist tmp bleibt weiterhin im Stack reserviert, bis die Funktion beendet wird. Das bedeutet auch, dass derselbe Stapelplatz von verschiedenen Variablen wiederverwendet werden kann (und wird), die ungefähr dieselbe “Lokalitätstiefe” in Geschwisterblöcken haben. Das Leerzeichen enthält den Wert der letzten Variablen, bis eine andere Variable, die in einer gleichgeordneten Blockvariablen deklariert ist, ihn überschreibt. In Ihrem Beispiel überschreibt niemand den zuvor belegten Speicherplatz tmpsodass Sie normalerweise den Wert sehen 17 in dieser Erinnerung unversehrt überleben.

Wenn Sie dies jedoch tun

int main(void) {
  volatile int *ptr;
  volatile int *ptrd;

  { // Block
    int tmp = 17;
    ptr = &tmp; // Just to see if the memory is cleared
  }

  { // Sibling block
    int d = 5;
    ptrd = &d;
  }

  printf("ptr = %d %d\n", *ptr, *ptrd);
  printf("%p %p\n", ptr, ptrd);
}

Sie werden sehen, dass der Raum früher von besetzt war tmp wurde für wiederverwendet d und sein früherer Wert wurde überschrieben. Der Zweite printf wird normalerweise denselben Zeigerwert für beide Zeiger ausgeben.

Die Lebensdauer eines automatischen Objekts endet am Ende des Blocks, in dem es deklariert ist.

Der Zugriff auf ein Objekt außerhalb seiner Lebensdauer ist ein undefiniertes Verhalten in C.

(C99, 6.2.4p2) “Wenn auf ein Objekt außerhalb seiner Lebensdauer verwiesen wird, ist das Verhalten undefiniert. Der Wert eines Zeigers wird unbestimmt, wenn das Objekt, auf das er zeigt, das Ende seiner Lebensdauer erreicht.”

Lokale Variablen werden auf dem Stack allokiert. Sie werden nicht in dem Sinne “freigegeben”, wie Sie es von GC-Sprachen oder dem auf dem Heap zugewiesenen Speicher erwarten. Sie verlassen einfach den Gültigkeitsbereich, und für eingebaute Typen wird der Code nichts tun – und für Objekte wird der Destruktor aufgerufen.

Der Zugriff auf sie außerhalb ihres Bereichs ist undefiniertes Verhalten. Sie hatten einfach Glück, da kein anderer Code diesen Speicherbereich überschrieben hat … noch nicht.

1443810cookie-checkWas passiert, wenn eine Variable den Gültigkeitsbereich verlässt?

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

Privacy policy