Wenn ich eine Variable innerhalb eines neuen Satzes von geschweiften Klammern erstelle, ist diese Variable dann auf der schließenden Klammer vom Stapel gefallen oder hängt sie bis zum Ende der Funktion? Beispielsweise:
void foo() {
int c[100];
{
int d[200];
}
//code that takes a while
return;
}
Wird d
während des code that takes a while
Abschnitts Speicherplatz beanspruchen?
Antworten:
Nein, geschweifte Klammern fungieren nicht als Stapelrahmen. In C bezeichnen geschweifte Klammern nur einen Namensbereich, aber nichts wird zerstört und nichts wird vom Stapel gesprungen, wenn die Kontrolle darüber ausfällt.
Als Programmierer, der Code schreibt, kann man sich das oft so vorstellen, als wäre es ein Stapelrahmen. Die in den geschweiften Klammern deklarierten Bezeichner sind nur innerhalb der geschweiften Klammern zugänglich. Aus Sicht eines Programmierers ist es also so, als würden sie beim Deklarieren auf den Stapel geschoben und dann beim Verlassen des Bereichs geöffnet. Compiler müssen jedoch keinen Code generieren, der beim Ein- / Ausstieg etwas pusht / platzt (und im Allgemeinen auch nicht).
Beachten Sie auch, dass lokale Variablen möglicherweise überhaupt keinen Stapelspeicher belegen: Sie können in CPU-Registern oder an einem anderen zusätzlichen Speicherort gespeichert oder vollständig optimiert werden.
d
Theoretisch könnte das Array also Speicher für die gesamte Funktion verbrauchen. Der Compiler kann es jedoch optimieren oder seinen Speicher mit anderen lokalen Variablen teilen, deren Nutzungsdauer sich nicht überschneidet.quelle
Die Zeit, in der die Variable tatsächlich Speicher belegt, ist offensichtlich vom Compiler abhängig (und viele Compiler passen den Stapelzeiger nicht an, wenn innere Blöcke innerhalb von Funktionen eingegeben und verlassen werden).
Eine eng verwandte, aber möglicherweise interessantere Frage ist jedoch, ob das Programm auf dieses innere Objekt außerhalb des inneren Bereichs (aber innerhalb der enthaltenden Funktion) zugreifen darf, dh:
(Mit anderen Worten: Darf der Compiler die Zuordnung aufheben
d
, auch wenn dies in der Praxis die meisten nicht tun?)Die Antwort ist , dass der Compiler ist ausplanen erlaubt
d
, und den Zugriff auf,p[0]
wo der Kommentar angibt , nicht definiertes Verhalten (das Programm ist nicht das innere Objekt außerhalb des inneren Umfangs für den Zugriff erlaubt). Der relevante Teil des C-Standards ist 6.2.4p5:quelle
Ihre Frage ist nicht klar genug, um eindeutig beantwortet zu werden.
Einerseits führen Compiler normalerweise keine lokale Speicherzuweisung-Freigabe für verschachtelte Blockbereiche durch. Der lokale Speicher wird normalerweise nur einmal beim Funktionseingang zugewiesen und beim Funktionsende freigegeben.
Wenn andererseits die Lebensdauer eines lokalen Objekts endet, kann der von diesem Objekt belegte Speicher später für ein anderes lokales Objekt wiederverwendet werden. Zum Beispiel in diesem Code
Beide Arrays belegen normalerweise denselben Speicherbereich, was bedeutet, dass die Gesamtmenge des von der Funktion benötigten lokalen Speichers
foo
für das größte von zwei Arrays erforderlich ist , nicht für beide gleichzeitig.Ob letzterer
d
im Kontext Ihrer Frage weiterhin bis zum Ende der Funktion das Gedächtnis belegt, müssen Sie selbst entscheiden.quelle
Es ist implementierungsabhängig. Ich habe ein kurzes Programm geschrieben, um zu testen, was gcc 4.3.4 macht, und es ordnet zu Beginn der Funktion den gesamten Stapelspeicher auf einmal zu. Sie können die von gcc erzeugte Assembly mit dem Flag -S untersuchen.
quelle
Nein, d [] befindet sich für den Rest der Routine nicht auf dem Stapel. Aber alloca () ist anders.
Bearbeiten: Kristopher Johnson (und Simon und Daniel) haben Recht , und meine erste Antwort war falsch . Mit gcc 4.3.4.on CYGWIN lautet der Code:
gibt:
Lebe und lerne! Und ein schneller Test scheint zu zeigen, dass AndreyT auch bei mehreren Zuordnungen korrekt ist.
Viel später hinzugefügt : Der obige Test zeigt, dass die gcc-Dokumentation nicht ganz richtig ist. Seit Jahren heißt es (Hervorhebung hinzugefügt):
quelle
alloca
Funktion auf. Ich bin wirklich überrascht, dass Cygwin GCC das tun würde. Es ist nicht einmal ein Array mit variabler Länge, also IDK, warum Sie das ansprechen.Sie könnten. Sie könnten nicht. Die Antwort, die Sie meiner Meinung nach wirklich brauchen, lautet: Nehmen Sie niemals etwas an. Moderne Compiler machen alle Arten von Architektur und implementierungsspezifischer Magie. Schreiben Sie Ihren Code einfach und leserlich an Menschen und lassen Sie den Compiler die guten Dinge tun. Wenn Sie versuchen, um den Compiler herum zu programmieren, fragen Sie nach Problemen - und die Probleme, die Sie normalerweise in diesen Situationen bekommen, sind normalerweise schrecklich subtil und schwer zu diagnostizieren.
quelle
Ihre Variable
d
wird normalerweise nicht vom Stapel genommen. Geschweifte Klammern bezeichnen keinen Stapelrahmen. Andernfalls könnten Sie so etwas nicht tun:Wenn geschweifte Klammern einen echten Stack-Push / Pop verursachen würden (wie es ein Funktionsaufruf tun würde), würde der obige Code nicht kompiliert werden, da der Code in den Klammern nicht auf die Variable zugreifen könnte
var
, die außerhalb der Klammern lebt (genau wie ein Unter-) Funktion kann nicht direkt auf Variablen in der aufrufenden Funktion zugreifen). Wir wissen, dass dies nicht der Fall ist.Geschweifte Klammern werden einfach zum Scoping verwendet. Der Compiler behandelt jeden Zugriff auf die "innere" Variable von außerhalb der umschließenden Klammern als ungültig und verwendet diesen Speicher möglicherweise für etwas anderes (dies ist implementierungsabhängig). Es kann jedoch nicht vom Stapel entfernt werden, bis die umschließende Funktion zurückkehrt.
Update: Hier ist, was die C-Spezifikation zu sagen hat. In Bezug auf Objekte mit automatischer Speicherdauer (Abschnitt 6.4.2):
Der gleiche Abschnitt definiert den Begriff "Lebensdauer" als (Schwerpunkt Mine):
Das Schlüsselwort hier ist natürlich "garantiert". Sobald Sie den Bereich des inneren Satzes von geschweiften Klammern verlassen, ist die Lebensdauer des Arrays abgelaufen. Möglicherweise wird noch Speicher dafür zugewiesen (Ihr Compiler verwendet den Speicherplatz möglicherweise für etwas anderes), aber alle Versuche, auf das Array zuzugreifen, rufen undefiniertes Verhalten hervor und führen zu unvorhersehbaren Ergebnissen.
Die C-Spezifikation kennt keine Stapelrahmen. Es spricht nur das Verhalten des resultierenden Programms an und überlässt die Implementierungsdetails dem Compiler (schließlich würde die Implementierung auf einer stapellosen CPU ganz anders aussehen als auf einer CPU mit einem Hardware-Stapel). In der C-Spezifikation gibt es nichts, was vorschreibt, wo ein Stapelrahmen enden wird oder nicht. Die einzige wirkliche Möglichkeit zu wissen , ist , den Code auf Ihre speziellen Compiler / Plattform zu kompilieren und die resultierende Anordnung zu untersuchen. Die aktuellen Optimierungsoptionen Ihres Compilers werden wahrscheinlich auch hier eine Rolle spielen.
Wenn Sie sicherstellen möchten , dass die Anordnung
d
nicht mehr Speicher zu essen, während der Code ausgeführt wird , können Sie entweder den Code in geschweiften Klammern in eine separate Funktion umwandeln oder explizitmalloc
undfree
dem Speicher statt mit dynamischem Speicher.quelle
Ich glaube, dass es außerhalb des Gültigkeitsbereichs liegt, aber erst dann vom Stapel genommen wird, wenn die Funktion zurückkehrt. Es nimmt also weiterhin Speicher auf dem Stapel ein, bis die Funktion abgeschlossen ist, ist jedoch stromabwärts der ersten schließenden geschweiften Klammer nicht zugänglich.
quelle
Es wurden bereits viele Informationen zu dem Standard gegeben, die darauf hinweisen, dass er tatsächlich implementierungsspezifisch ist.
Ein Experiment könnte also von Interesse sein. Wenn wir den folgenden Code versuchen:
Mit gcc erhalten wir hier zweimal die gleiche Adresse: Coliro
Aber wenn wir den folgenden Code versuchen:
Mit gcc erhalten wir hier zwei verschiedene Adressen: Coliro
Sie können sich also nicht sicher sein, was los ist.
quelle