Haben Sie versucht, dies einzugeben und sich selbst davon zu überzeugen?
Wilhelmtell
20
Ich möchte verstehen warum.
Vadiklk
7
@ Vadiklk so stellen Sie Frage beginnend mit "Warum"
Andrey
1
ideone.com/t9Bbe Was würden Sie erwarten? Entspricht das Ergebnis nicht Ihren Erwartungen? Warum haben Sie Ihr Ergebnis erwartet?
eckes
Antworten:
185
Hier gibt es zwei Probleme: Lebensdauer und Umfang.
Im Bereich der Variablen kann der Variablenname angezeigt werden. Hier ist x nur innerhalb der Funktion foo () sichtbar.
Die Lebensdauer einer Variablen ist der Zeitraum, über den sie existiert. Wenn x ohne das Schlüsselwort static definiert würde, würde die Lebensdauer vom Eintrag in foo () bis zur Rückkehr von foo () reichen. Daher wird es bei jedem Anruf auf 5 neu initialisiert.
Das Schlüsselwort static verlängert die Lebensdauer einer Variablen auf die Lebensdauer des Programms. zB erfolgt die Initialisierung nur einmal und dann behält die Variable ihren Wert - was auch immer sie geworden ist - bei allen zukünftigen Aufrufen von foo () bei.
In welchen Szenarien müssen wir eine Variable innerhalb einer Funktion als statisch deklarieren? Nur neugierig zu wissen, da ich dies noch nicht verwendet habe?
Akay
Ich würde mich bedanken, aber das alles wurde ganz oben auf der Seite beantwortet. Es bringt mich zum Lachen, dass die Leute nicht nur ihren eigenen Code ausführen. xD
Pfütze
Diese Antwort ist falsch. In dem Moment, in dem Sie über rekursive Funktionen nachdenken, erklären die hier beschriebenen Definitionen das Verhalten nicht!
Philip Couling
52
Ausgabe : 6 7
Grund : Die statische Variable wird nur einmal initialisiert (im Gegensatz zur automatischen Variablen) und die weitere Definition der statischen Variablen wird zur Laufzeit umgangen. Und wenn es nicht manuell initialisiert wird, wird es automatisch mit dem Wert 0 initialisiert. So,
void foo(){staticint x =5;// assigns value of 5 only once
x++;
printf("%d", x);}int main(){
foo();// x = 6
foo();// x = 7return0;}
staticint x =5;void foo(){
x++;
printf("%d", x);}int main(){
foo();
foo();return0;}
Alles, was das statische Schlüsselwort in diesem Programm bewirkt, ist, dass es dem Compiler (im Wesentlichen) mitteilt: "Hey, ich habe hier eine Variable, auf die niemand anderes zugreifen soll. Sagen Sie niemandem, dass sie existiert."
Innerhalb einer Methode teilt das statische Schlüsselwort dem Compiler das gleiche wie oben mit, aber auch: "Sagen Sie niemandem, dass dies außerhalb dieser Funktion existiert, es sollte nur innerhalb dieser Funktion zugänglich sein".
Nun, es ist eigentlich nicht dasselbe. Bei X gibt es immer noch das Problem des Gültigkeitsbereichs. In diesem Beispiel können Sie hauptsächlich mit stupsen und fummeln x. es ist global. Im ursprünglichen Beispiel xwar foo lokal und nur in diesem Block sichtbar, was im Allgemeinen vorzuziehen ist: Wenn foo vorhanden ist, um xauf vorhersehbare und sichtbare Weise zu warten , ist es im Allgemeinen gefährlich, andere stoßen zu lassen. Als weiterer Vorteil, wenn es im Umfang foo() bleibt, bleibt es auch foo()tragbar.
user2149140
2
@ user2149140 'Sag niemandem, dass dies außerhalb dieser Funktion existiert, es sollte nur innerhalb dieser Funktion zugänglich sein'
DCShannon
3
Während Sie das Problem des Gültigkeitsbereichs aufgrund der Deklaration der Variablen angesprochen haben, scheint die Beschreibung von statisch, die den Gültigkeitsbereich und nicht die Lebensdauer beeinflusst, falsch zu sein.
DCShannon
1
@Chameleon Die Frage ist mit gekennzeichnet. cIn diesem Zusammenhang wäre Ihr Beispiel im globalen Bereich illegal. (C erfordert konstante Initialisierer für Globals, C ++ nicht).
Richard J. Ross III
5
Eine statische Variable innerhalb einer Funktion hat eine Lebensdauer, solange Ihr Programm ausgeführt wird. Es wird nicht jedes Mal zugewiesen, wenn Ihre Funktion aufgerufen und freigegeben wird, wenn Ihre Funktion zurückkehrt.
Zu sagen, dass dies wie eine "globale" Variable ist, und dann zu sagen, dass Sie nicht darauf zugreifen können, ist ein Oxymoron. Global bedeutet überall zugänglich. Was in diesem Fall einer statischen INSIDE-Funktion NICHT überall zugänglich ist. Wie andere angemerkt haben, geht es bei OP um Umfang und Lebensdauer. Bitte verwechseln Sie die Leute nicht damit, den Begriff "global" zu verwenden und sie über den Umfang der Variablen irrezuführen.
ChuckB
@ChuckB: Richtig. Behoben. Nun, es ist 6 Jahre her. Meine vorherige Antwort hatte die Wahrnehmung von vor 6 Jahren!
Donotalo
5
Ausgabe: 6,7
Grund
Die Deklaration von xist innerhalb, fooaber die x=5Initialisierung erfolgt außerhalb von foo!
Was wir hier verstehen müssen, ist das
staticint x =5;
ist nicht dasselbe wie
staticint x;
x =5;
Andere Antworten haben die wichtigen Wörter hier verwendet, Umfang und Lebensdauer, und darauf hingewiesen, dass der Umfang von xvom Punkt seiner Deklaration in der Funktion foobis zum Ende der Funktion reicht foo. Zum Beispiel habe ich überprüft, indem ich die Deklaration an das Ende der Funktion xverschoben habe , und das macht bei der x++;Anweisung nicht deklariert .
Der static int x(Umfangs-) Teil der Anweisung gilt also tatsächlich dort, wo Sie ihn gelesen haben, irgendwo INNERHALB der Funktion und nur von da an, nicht darüber innerhalb der Funktion.
Der x = 5(lebenslange) Teil der Anweisung ist jedoch die Initialisierung der Variablen und das AUSSERHALB der Funktion als Teil des Programmladens. Die Variable xwird mit dem Wert geboren, 5wann das Programm geladen wird.
Ich habe dies in einem der Kommentare gelesen: " Außerdem wird hier nicht der wirklich verwirrende Teil angesprochen, nämlich die Tatsache, dass der Initialisierer bei nachfolgenden Aufrufen übersprungen wird. " Er wird bei allen Aufrufen übersprungen. Die Initialisierung der Variablen liegt außerhalb des eigentlichen Funktionscodes.
Der Wert 5 wird theoretisch unabhängig davon festgelegt, ob foo überhaupt aufgerufen wird oder nicht, obwohl ein Compiler die Funktion möglicherweise optimieren kann, wenn Sie sie nirgendwo aufrufen. Der Wert 5 sollte in der Variablen sein, bevor foo jemals aufgerufen wird.
Innerhalb von foowird durch die Anweisung static int x = 5;wahrscheinlich überhaupt kein Code generiert.
Ich fand die Adresse, die xverwendet wurde, als ich eine Funktion fooin ein Programm von mir einfügte, und vermutete dann (richtig), dass derselbe Speicherort verwendet würde, wenn ich das Programm erneut ausführen würde. Die folgende teilweise Bildschirmaufnahme zeigt, dass xder Wert 5bereits vor dem ersten Aufruf von vorliegt foo.
Die Ausgabe wird sein 6 7. Eine statische Variable (ob innerhalb einer Funktion oder nicht) wird genau einmal initialisiert, bevor eine Funktion in dieser Übersetzungseinheit ausgeführt wird. Danach behält es seinen Wert bei, bis es geändert wird.
Sind Sie sicher, dass die Statik vor dem Aufruf der Funktion und nicht beim ersten Aufruf der Funktion initialisiert wird?
Jesse Pepper
@ JessePepper: Zumindest wenn Speicher bereitgestellt wird, hängt dies davon ab, ob Sie über C ++ 98/03 oder C ++ 11 sprechen. In C ++ 98/03 glaube ich, dass es wie oben beschrieben ist. In C ++ 11 macht das Threading dies im Wesentlichen unmöglich, sodass die Initialisierung beim ersten Aufrufen der Funktion erfolgt.
Jerry Coffin
2
Ich denke du liegst tatsächlich falsch. Ich denke, sogar vor C ++ 11 wurde es nur initialisiert, als die Funktion aufgerufen wurde. Dies ist wichtig für eine gemeinsame Lösung des Problems der statischen Initialisierungsabhängigkeit.
Jesse Pepper
2
Vadiklk,
Warum ...? Grund dafür ist, dass statische Variablen nur einmal initialisiert werden und ihren Wert im gesamten Programm beibehalten. Das heißt, Sie können statische Variablen zwischen Funktionsaufrufen verwenden. Es kann auch verwendet werden, um zu zählen, "wie oft eine Funktion aufgerufen wird".
main(){staticint var =5;
printf("%d ",var--);if(var)
main();}
und die Antwort lautet 5 4 3 2 1 und nicht 5 5 5 5 5 5 .... (Endlosschleife), wie Sie es erwarten. Grund dafür ist, dass die statische Variable einmal initialisiert wird. Wenn main () das nächste Mal aufgerufen wird, wird sie nicht auf 5 initialisiert, da sie bereits im Programm initialisiert ist. Wir können den Wert also ändern, aber nicht neu initialisieren. So funktioniert statische Variable.
oder Sie können nach Speicher berücksichtigen: Statische Variablen werden im Datenabschnitt eines Programms gespeichert, und Variablen, die im Datenabschnitt gespeichert sind, werden einmal initialisiert. und vor der Initialisierung werden sie im BSS-Abschnitt gespeichert.
Im Gegenzug werden automatische (lokale) Variablen auf dem Stapel gespeichert und alle Variablen auf dem Stapel werden immer wieder neu initialisiert, wenn die Funktion aufgerufen wird, da dafür ein neuer FAR (Funktionsaktivierungsdatensatz) erstellt wird.
OK für mehr Verständnis, machen Sie das obige Beispiel ohne "statisch" und lassen Sie Sie wissen, was die Ausgabe sein wird. Das bringt Sie dazu, den Unterschied zwischen diesen beiden zu verstehen.
Statische lokale Variablen: Variablen, die innerhalb einer Funktion als statisch deklariert wurden, werden statisch zugewiesen und haben denselben Gültigkeitsbereich wie automatische lokale Variablen. Daher sind alle Werte, die die Funktion während eines Aufrufs in ihre statischen lokalen Variablen einfügt, beim erneuten Aufruf der Funktion weiterhin vorhanden.
Das ist schrecklich! "Variablen, die innerhalb einer Funktion als statisch deklariert sind, werden statisch zugewiesen" - es erklärt nichts, es sei denn, Sie wissen bereits, was es bedeutet!
@Blank: Nun, dafür dachte ich, der zweite Satz sei. Obwohl ich denke, dass Sie Recht haben, sollte es besser formuliert sein.
Andrew White
Dies spricht auch nicht den wirklich verwirrenden Teil an, nämlich die Tatsache, dass der Initialisierer bei nachfolgenden Aufrufen übersprungen wird.
Tom Auger
statisch zugeordnet bedeutet weder Stapel noch Haufen.
Chamäleon
1
Sie erhalten 6 7 gedruckt als, wie leicht zu testen ist, und hier ist der Grund: Beim fooersten Aufruf wird die statische Variable x auf 5 initialisiert. Dann wird sie auf 6 erhöht und gedruckt.
Nun zum nächsten Anruf bei foo. Das Programm überspringt die Initialisierung der statischen Variablen und verwendet stattdessen den Wert 6, der x beim letzten Mal zugewiesen wurde. Die Ausführung läuft wie gewohnt ab und gibt Ihnen den Wert 7.
x ist eine globale Variable, die nur von foo () aus sichtbar ist. 5 ist der Anfangswert, der im Abschnitt .data des Codes gespeichert ist. Jede nachfolgende Änderung überschreibt den vorherigen Wert. Im Funktionskörper wird kein Zuordnungscode generiert.
6 und 7 Da statische Variablen nur einmal initialisiert werden, wird 5 ++ beim ersten Aufruf zu 6. 6 ++ wird beim zweiten Aufruf zu 7. Hinweis: Beim zweiten Aufruf wird der x-Wert 6 anstelle von 5 verwendet, da x eine statische Variable ist.
Zumindest in C ++ 11 muss die Initialisierung beim ersten Aufruf der Funktion erfolgen, wenn der zum Initialisieren einer lokalen statischen Variablen verwendete Ausdruck kein 'constexpr' ist (kann vom Compiler nicht ausgewertet werden). Das einfachste Beispiel ist die direkte Verwendung eines Parameters zum Initialisieren der lokalen statischen Variablen. Daher muss der Compiler Code ausgeben, um zu erraten, ob der Aufruf der erste ist oder nicht, was wiederum eine lokale boolesche Variable erfordert. Ich habe ein solches Beispiel kompiliert und anhand des Assembly-Codes überprüft, ob dies der Fall ist. Das Beispiel kann folgendermaßen aussehen:
void f(int p ){staticconstint first_p = p ;
cout <<"first p == "<< p << endl ;}void main(){
f(1); f(2); f(3);}
Wenn der Ausdruck 'constexpr' lautet, ist dies natürlich nicht erforderlich, und die Variable kann beim Laden des Programms mithilfe eines vom Compiler im Code der Ausgabeassemblierung gespeicherten Werts initialisiert werden.
Antworten:
Hier gibt es zwei Probleme: Lebensdauer und Umfang.
Im Bereich der Variablen kann der Variablenname angezeigt werden. Hier ist x nur innerhalb der Funktion foo () sichtbar.
Die Lebensdauer einer Variablen ist der Zeitraum, über den sie existiert. Wenn x ohne das Schlüsselwort static definiert würde, würde die Lebensdauer vom Eintrag in foo () bis zur Rückkehr von foo () reichen. Daher wird es bei jedem Anruf auf 5 neu initialisiert.
Das Schlüsselwort static verlängert die Lebensdauer einer Variablen auf die Lebensdauer des Programms. zB erfolgt die Initialisierung nur einmal und dann behält die Variable ihren Wert - was auch immer sie geworden ist - bei allen zukünftigen Aufrufen von foo () bei.
quelle
Ausgabe : 6 7
Grund : Die statische Variable wird nur einmal initialisiert (im Gegensatz zur automatischen Variablen) und die weitere Definition der statischen Variablen wird zur Laufzeit umgangen. Und wenn es nicht manuell initialisiert wird, wird es automatisch mit dem Wert 0 initialisiert. So,
quelle
6 7
Der Compiler sorgt dafür, dass die Initialisierung statischer Variablen nicht bei jeder Eingabe der Funktion erfolgt
quelle
Dies entspricht dem folgenden Programm:
Alles, was das statische Schlüsselwort in diesem Programm bewirkt, ist, dass es dem Compiler (im Wesentlichen) mitteilt: "Hey, ich habe hier eine Variable, auf die niemand anderes zugreifen soll. Sagen Sie niemandem, dass sie existiert."
Innerhalb einer Methode teilt das statische Schlüsselwort dem Compiler das gleiche wie oben mit, aber auch: "Sagen Sie niemandem, dass dies außerhalb dieser Funktion existiert, es sollte nur innerhalb dieser Funktion zugänglich sein".
ich hoffe das hilft
quelle
x
. es ist global. Im ursprünglichen Beispielx
war foo lokal und nur in diesem Block sichtbar, was im Allgemeinen vorzuziehen ist: Wenn foo vorhanden ist, umx
auf vorhersehbare und sichtbare Weise zu warten , ist es im Allgemeinen gefährlich, andere stoßen zu lassen. Als weiterer Vorteil, wenn es im Umfangfoo()
bleibt, bleibt es auchfoo()
tragbar.c
In diesem Zusammenhang wäre Ihr Beispiel im globalen Bereich illegal. (C erfordert konstante Initialisierer für Globals, C ++ nicht).Eine statische Variable innerhalb einer Funktion hat eine Lebensdauer, solange Ihr Programm ausgeführt wird. Es wird nicht jedes Mal zugewiesen, wenn Ihre Funktion aufgerufen und freigegeben wird, wenn Ihre Funktion zurückkehrt.
quelle
Ausgabe: 6,7
Grund
Die Deklaration von
x
ist innerhalb,foo
aber diex=5
Initialisierung erfolgt außerhalb vonfoo
!Was wir hier verstehen müssen, ist das
ist nicht dasselbe wie
Andere Antworten haben die wichtigen Wörter hier verwendet, Umfang und Lebensdauer, und darauf hingewiesen, dass der Umfang von
x
vom Punkt seiner Deklaration in der Funktionfoo
bis zum Ende der Funktion reichtfoo
. Zum Beispiel habe ich überprüft, indem ich die Deklaration an das Ende der Funktionx
verschoben habe , und das macht bei derx++;
Anweisung nicht deklariert .Der
static int x
(Umfangs-) Teil der Anweisung gilt also tatsächlich dort, wo Sie ihn gelesen haben, irgendwo INNERHALB der Funktion und nur von da an, nicht darüber innerhalb der Funktion.Der
x = 5
(lebenslange) Teil der Anweisung ist jedoch die Initialisierung der Variablen und das AUSSERHALB der Funktion als Teil des Programmladens. Die Variablex
wird mit dem Wert geboren,5
wann das Programm geladen wird.Ich habe dies in einem der Kommentare gelesen: " Außerdem wird hier nicht der wirklich verwirrende Teil angesprochen, nämlich die Tatsache, dass der Initialisierer bei nachfolgenden Aufrufen übersprungen wird. " Er wird bei allen Aufrufen übersprungen. Die Initialisierung der Variablen liegt außerhalb des eigentlichen Funktionscodes.
Der Wert 5 wird theoretisch unabhängig davon festgelegt, ob foo überhaupt aufgerufen wird oder nicht, obwohl ein Compiler die Funktion möglicherweise optimieren kann, wenn Sie sie nirgendwo aufrufen. Der Wert 5 sollte in der Variablen sein, bevor foo jemals aufgerufen wird.
Innerhalb von
foo
wird durch die Anweisungstatic int x = 5;
wahrscheinlich überhaupt kein Code generiert.Ich fand die Adresse, die
x
verwendet wurde, als ich eine Funktionfoo
in ein Programm von mir einfügte, und vermutete dann (richtig), dass derselbe Speicherort verwendet würde, wenn ich das Programm erneut ausführen würde. Die folgende teilweise Bildschirmaufnahme zeigt, dassx
der Wert5
bereits vor dem ersten Aufruf von vorliegtfoo
.quelle
Die Ausgabe wird sein
6 7
. Eine statische Variable (ob innerhalb einer Funktion oder nicht) wird genau einmal initialisiert, bevor eine Funktion in dieser Übersetzungseinheit ausgeführt wird. Danach behält es seinen Wert bei, bis es geändert wird.quelle
Vadiklk,
Warum ...? Grund dafür ist, dass statische Variablen nur einmal initialisiert werden und ihren Wert im gesamten Programm beibehalten. Das heißt, Sie können statische Variablen zwischen Funktionsaufrufen verwenden. Es kann auch verwendet werden, um zu zählen, "wie oft eine Funktion aufgerufen wird".
und die Antwort lautet 5 4 3 2 1 und nicht 5 5 5 5 5 5 .... (Endlosschleife), wie Sie es erwarten. Grund dafür ist, dass die statische Variable einmal initialisiert wird. Wenn main () das nächste Mal aufgerufen wird, wird sie nicht auf 5 initialisiert, da sie bereits im Programm initialisiert ist. Wir können den Wert also ändern, aber nicht neu initialisieren. So funktioniert statische Variable.
oder Sie können nach Speicher berücksichtigen: Statische Variablen werden im Datenabschnitt eines Programms gespeichert, und Variablen, die im Datenabschnitt gespeichert sind, werden einmal initialisiert. und vor der Initialisierung werden sie im BSS-Abschnitt gespeichert.
Im Gegenzug werden automatische (lokale) Variablen auf dem Stapel gespeichert und alle Variablen auf dem Stapel werden immer wieder neu initialisiert, wenn die Funktion aufgerufen wird, da dafür ein neuer FAR (Funktionsaktivierungsdatensatz) erstellt wird.
OK für mehr Verständnis, machen Sie das obige Beispiel ohne "statisch" und lassen Sie Sie wissen, was die Ausgabe sein wird. Das bringt Sie dazu, den Unterschied zwischen diesen beiden zu verstehen.
Danke Javed
quelle
Lesen wir einfach den Wikipedia-Artikel über statische Variablen ...
quelle
Sie erhalten 6 7 gedruckt als, wie leicht zu testen ist, und hier ist der Grund: Beim
foo
ersten Aufruf wird die statische Variable x auf 5 initialisiert. Dann wird sie auf 6 erhöht und gedruckt.Nun zum nächsten Anruf bei
foo
. Das Programm überspringt die Initialisierung der statischen Variablen und verwendet stattdessen den Wert 6, der x beim letzten Mal zugewiesen wurde. Die Ausführung läuft wie gewohnt ab und gibt Ihnen den Wert 7.quelle
x ist eine globale Variable, die nur von foo () aus sichtbar ist. 5 ist der Anfangswert, der im Abschnitt .data des Codes gespeichert ist. Jede nachfolgende Änderung überschreibt den vorherigen Wert. Im Funktionskörper wird kein Zuordnungscode generiert.
quelle
6 und 7 Da statische Variablen nur einmal initialisiert werden, wird 5 ++ beim ersten Aufruf zu 6. 6 ++ wird beim zweiten Aufruf zu 7. Hinweis: Beim zweiten Aufruf wird der x-Wert 6 anstelle von 5 verwendet, da x eine statische Variable ist.
quelle
Zumindest in C ++ 11 muss die Initialisierung beim ersten Aufruf der Funktion erfolgen, wenn der zum Initialisieren einer lokalen statischen Variablen verwendete Ausdruck kein 'constexpr' ist (kann vom Compiler nicht ausgewertet werden). Das einfachste Beispiel ist die direkte Verwendung eines Parameters zum Initialisieren der lokalen statischen Variablen. Daher muss der Compiler Code ausgeben, um zu erraten, ob der Aufruf der erste ist oder nicht, was wiederum eine lokale boolesche Variable erfordert. Ich habe ein solches Beispiel kompiliert und anhand des Assembly-Codes überprüft, ob dies der Fall ist. Das Beispiel kann folgendermaßen aussehen:
Wenn der Ausdruck 'constexpr' lautet, ist dies natürlich nicht erforderlich, und die Variable kann beim Laden des Programms mithilfe eines vom Compiler im Code der Ausgabeassemblierung gespeicherten Werts initialisiert werden.
quelle