Co zostanie wydrukowane? 6 6 czy 6 7? I dlaczego?
void foo()
{
static int x = 5;
x++;
printf("%d", x);
}
int main()
{
foo();
foo();
return 0;
}
Co zostanie wydrukowane? 6 6 czy 6 7? I dlaczego?
void foo()
{
static int x = 5;
x++;
printf("%d", x);
}
int main()
{
foo();
foo();
return 0;
}
Odpowiedzi:
Są tu dwie kwestie: czas życia i zakres.
Zakres zmiennej to miejsce, w którym można zobaczyć nazwę zmiennej. Tutaj x jest widoczne tylko wewnątrz funkcji foo ().
Czas życia zmiennej to okres, w którym ona istnieje. Gdyby x zostało zdefiniowane bez słowa kluczowego static, okres istnienia trwałby od wejścia do foo () do powrotu z foo (); więc przy każdym wywołaniu zostanie ponownie zainicjowany na 5.
Słowo kluczowe static działa w celu przedłużenia czasu życia zmiennej do czasu życia programu; np. inicjalizacja następuje raz i tylko raz, po czym zmienna zachowuje swoją wartość - cokolwiek się pojawiła - przez wszystkie przyszłe wywołania funkcji foo ().
Wyjście : 6 7
Powód : zmienna statyczna jest inicjowana tylko raz (w przeciwieństwie do zmiennej automatycznej), a dalsze definiowanie zmiennej statycznej byłoby pomijane podczas działania. A jeśli nie zostanie zainicjowany ręcznie, zostanie zainicjalizowany wartością 0 automatycznie. Więc,
void foo() {
static int x = 5; // assigns value of 5 only once
x++;
printf("%d", x);
}
int main() {
foo(); // x = 6
foo(); // x = 7
return 0;
}
6 7
kompilator ustala, że inicjalizacja zmiennej statycznej nie występuje za każdym razem, gdy funkcja jest wprowadzana
To to samo, co posiadanie następującego programu:
static int x = 5;
void foo()
{
x++;
printf("%d", x);
}
int main()
{
foo();
foo();
return 0;
}
Jedyne, co robi słowo kluczowe static w tym programie, polega na tym, że mówi kompilatorowi (zasadniczo) „hej, mam tutaj zmienną, do której nie chcę, aby ktokolwiek inny miał dostęp, nie mów nikomu, że istnieje”.
Wewnątrz metody słowo kluczowe static mówi kompilatorowi to samo, co powyżej, ale także „nie mów nikomu, że istnieje poza tą funkcją, powinno być dostępne tylko wewnątrz tej funkcji”.
mam nadzieję, że to pomoże
x
in main; jest globalna. W oryginalnym przykładzie x
był lokalny dla foo, widoczny tylko wewnątrz tego bloku, co jest generalnie preferowane: jeśli foo istnieje, aby utrzymać się x
w przewidywalny i widoczny sposób, to pozwalanie innym szturchać go jest generalnie niebezpieczne. Kolejną korzyścią płynącą z utrzymywania go w zasięgu jest foo()
również możliwość foo()
przenoszenia.
c
, więc w tym kontekście Twój przykład byłby nielegalny w zakresie globalnym. (C wymaga stałych inicjatorów dla zmiennych globalnych, C ++ nie).
Zmienna statyczna wewnątrz funkcji ma żywotność tak długo, jak długo działa Twój program. Nie zostanie on przydzielony za każdym razem, gdy funkcja zostanie wywołana i zwolniona, gdy funkcja zostanie zwrócona.
Deklaracja x
jest wewnątrz, foo
ale x=5
inicjalizacja odbywa się poza foo
!
To, co musimy tutaj zrozumieć, to to
static int x = 5;
to nie to samo co
static int x;
x = 5;
Inne odpowiedzi używały tutaj ważnych słów, zakresu i czasu życia, i wskazywały, że zakres x
jest od punktu jego deklaracji w funkcji foo
do końca funkcji foo
. Na przykład sprawdziłem, przenosząc deklarację na koniec funkcji, a to powoduje, że instrukcja jest x
niezadeklarowana x++;
.
Zatem static int x
(zakres) część instrukcji faktycznie ma zastosowanie tam, gdzie ją czytasz, gdzieś WEWNĄTRZ funkcji i tylko od tego miejsca, a nie nad nią wewnątrz funkcji.
Jednak x = 5
(życia) częścią instrukcji jest inicjalizacja zmiennej i dzieje się POZA funkcji jako część ładowania programu. Zmienna x
rodzi się z wartością w 5
momencie wczytywania programu.
Przeczytałem o tym w jednym z komentarzy: „ Poza tym nie dotyczy to naprawdę zagmatwanej części, jaką jest fakt, że inicjalizator jest pomijany przy kolejnych wywołaniach. ” Jest pomijany we wszystkich wywołaniach. Inicjalizacja zmiennej jest poza właściwym kodem funkcji.
Wartość 5 jest teoretycznie ustawiana niezależnie od tego, czy foo jest w ogóle wywoływane, chociaż kompilator może zoptymalizować tę funkcję, jeśli nie wywołasz jej nigdzie. Wartość 5 powinna znajdować się w zmiennej przed wywołaniem foo.
Wewnątrz jest mało prawdopodobne foo
, że instrukcja static int x = 5;
w ogóle wygeneruje kod.
Znalazłem adres x
używany, gdy umieściłem funkcję foo
w moim programie, a następnie (poprawnie) zgadłem, że ta sama lokalizacja zostanie użyta, gdy ponownie uruchomię program. Zrzut ekranu częściowy poniżej pokazuje, że x
ma wartość 5
nawet przed pierwszym wywołaniem foo
.
Dane wyjściowe będą 6 7
. Zmienna statyczna (czy to wewnątrz funkcji, czy nie) jest inicjowana dokładnie raz, przed wykonaniem jakiejkolwiek funkcji w tej jednostce tłumaczeniowej. Następnie zachowuje swoją wartość do czasu modyfikacji.
Vadiklk,
Czemu ...? Powodem jest to, że zmienna statyczna jest inicjowana tylko raz i zachowuje swoją wartość przez cały program. oznacza, że możesz używać zmiennej statycznej między wywołaniami funkcji. można go również użyć do obliczenia „ile razy wywoływana jest funkcja”
main()
{
static int var = 5;
printf("%d ",var--);
if(var)
main();
}
a odpowiedź to 5 4 3 2 1, a nie 5 5 5 5 5 5 .... (nieskończona pętla), jak się spodziewasz. ponownie, przyczyna jest taka, że zmienna statyczna jest inicjalizowana raz, przy następnym wywołaniu funkcji main () nie zostanie zainicjalizowana na 5, ponieważ jest już zainicjowana w programie, więc możemy zmienić wartość, ale nie możemy jej ponownie zainicjować. Tak działa zmienna statyczna.
lub możesz rozważyć to jako pamięć: zmienne statyczne są przechowywane w sekcji danych programu, a zmienne przechowywane w sekcji danych są inicjowane raz. a przed inicjalizacją są przechowywane w sekcji BSS.
Z kolei zmienne Auto (lokalne) są przechowywane na stosie, a wszystkie zmienne na stosie są ponownie inicjowane przez cały czas, gdy funkcja jest wywoływana jako nowy FAR (rekord aktywacji funkcji).
ok dla lepszego zrozumienia, zrób powyższy przykład bez "statycznego" i daj znać, jaki będzie wynik. To sprawi, że zrozumiesz różnicę między tymi dwoma.
Dzięki Javed
Przeczytajmy tylko artykuł Wikipedii o zmiennych statycznych ...
Statyczne zmienne lokalne: zmienne zadeklarowane jako statyczne wewnątrz funkcji są przydzielane statycznie, mając taki sam zakres jak automatyczne zmienne lokalne. W związku z tym wszelkie wartości, które funkcja umieści w statycznych zmiennych lokalnych podczas jednego wywołania, będą nadal obecne, gdy funkcja zostanie wywołana ponownie.
Otrzymasz 6 7 wydrukowane tak, jak to łatwo przetestować, a oto powód: Przy foo
pierwszym wywołaniu zmienna statyczna x jest inicjalizowana na 5. Następnie jest zwiększana do 6 i drukowana.
A teraz następne wezwanie do foo
. Program pomija inicjalizację zmiennej statycznej i zamiast tego używa wartości 6, która została przypisana x ostatnim razem. Wykonanie przebiega normalnie, dając wartość 7.
6 i 7 Ponieważ zmienna statyczna pojawia się tylko raz, więc 5 ++ staje się 6 przy pierwszym wywołaniu 6 ++ staje się 7 przy drugim wywołaniu Uwaga - kiedy następuje drugie wywołanie, przyjmuje wartość x równą 6 zamiast 5, ponieważ x jest zmienną statyczną.
Przynajmniej w C ++ 11, gdy wyrażenie użyte do zainicjowania lokalnej zmiennej statycznej nie jest „constexpr” (nie może być ocenione przez kompilator), wówczas inicjalizacja musi nastąpić podczas pierwszego wywołania funkcji. Najprostszym przykładem jest bezpośrednie użycie parametru do zainicjowania lokalnej zmiennej statycznej. Dlatego kompilator musi wyemitować kod, aby odgadnąć, czy wywołanie jest pierwsze, czy nie, co z kolei wymaga lokalnej zmiennej boolowskiej. Skompilowałem taki przykład i sprawdziłem, czy to prawda, widząc kod asemblera. Przykład może wyglądać tak:
void f( int p )
{
static const int first_p = p ;
cout << "first p == " << p << endl ;
}
void main()
{
f(1); f(2); f(3);
}
oczywiście, gdy wyrażeniem jest „constexpr”, to nie jest to wymagane i zmienną można zainicjować podczas ładowania programu przy użyciu wartości przechowywanej przez kompilator w wyjściowym kodzie assemblera.