Słowo kluczowe „statyczne” w języku C ma dwa zasadniczo różne znaczenia.
Ograniczenie zakresu
W tym kontekście „static” łączy się z „extern”, aby kontrolować zakres nazwy zmiennej lub funkcji. Static powoduje, że nazwa zmiennej lub funkcji jest dostępna tylko w jednej jednostce kompilacji i dostępna tylko dla kodu, który istnieje po deklaracji / definicji w tekście jednostki kompilacji.
To ograniczenie samo w sobie ma znaczenie tylko wtedy i tylko wtedy, gdy masz więcej niż jedną jednostkę kompilacji w swoim projekcie. Jeśli masz tylko jedną jednostkę kompilacji, nadal działa, ale te efekty są w większości bezcelowe (chyba że lubisz kopać w plikach obiektowych, aby przeczytać, co wygenerował kompilator).
Jak zauważono, to słowo kluczowe w tym kontekście łączy się ze słowem kluczowym „extern”, które działa odwrotnie - dzięki temu, że nazwa zmiennej lub funkcji jest połączona z tą samą nazwą, którą można znaleźć w innych jednostkach kompilacji. Możesz więc spojrzeć na „statyczny” jako wymagający, aby zmienna lub nazwa znajdowała się w bieżącej jednostce kompilacji, podczas gdy „extern” umożliwia łączenie jednostek cross-kompilacji.
Statyczny okres istnienia
Statyczny czas życia oznacza, że zmienna istnieje przez cały czas trwania programu (nieważne, jak długo to trwa). Kiedy używasz „statycznej” do deklarowania / definiowania zmiennej w funkcji, oznacza to, że zmienna jest tworzona jakiś czas przed jej pierwsze użycie (co oznacza, że za każdym razem, gdy tego doświadczyłem, zmienna jest tworzona przed uruchomieniem funkcji main ()) i nie jest później niszczona. Nawet wtedy, gdy wykonanie funkcji jest zakończone i powraca do wywołującego. I tak jak statyczne zmienne czasu życia zadeklarowane poza funkcjami, są one inicjowane w tym samym momencie - przed uruchomieniem funkcji main () - do semantycznego zera (jeśli nie podano inicjalizacji) lub do określonej jawnej wartości, jeśli została podana.
Różni się to od zmiennych funkcji typu „auto”, które są tworzone jako nowe (lub jakby nowe) za każdym razem, gdy funkcja jest wprowadzana, a następnie są niszczone (lub, jakby zostały zniszczone), gdy funkcja kończy działanie .
W przeciwieństwie do wpływu zastosowania „statycznej” na definicję zmiennej poza funkcją, co bezpośrednio wpływa na jej zakres, zadeklarowanie zmiennej funkcji (oczywiście w treści funkcji) jako „statyczna” ma nie wpływ na jego zakres. Zakres jest określony przez fakt, że został zdefiniowany w treści funkcji. Statyczne zmienne czasu życia zdefiniowane w funkcjach mają taki sam zakres, jak inne zmienne „auto” zdefiniowane w treściach funkcji - zakres funkcji.
Podsumowanie
Zatem słowo kluczowe „statyczne” ma różne konteksty, co oznacza „bardzo różne znaczenia”. Powodem, dla którego został użyty na dwa sposoby, jak ten, było unikanie używania innego słowa kluczowego. (Odbyła się długa dyskusja na ten temat.) Uznano, że programiści mogą tolerować użycie, a wartość unikania kolejnego słowa kluczowego w języku była ważniejsza (niż argumenty w innym przypadku).
(Wszystkie zmienne zadeklarowane poza funkcjami mają statyczny okres istnienia i nie potrzebują słowa kluczowego „static”, aby było to prawdą. Dzięki temu słowo kluczowe, które było tam używane, zostało zwolnione i oznaczało coś zupełnie innego: pojedyncza jednostka kompilacji. ”To swego rodzaju hack).
Szczegółowa uwaga
statyczny lotny bez znaku PORTB @ 0x06;
Słowo „statyczny” w tym miejscu należy interpretować w ten sposób, że konsolidator nie będzie próbował dopasować wielu wystąpień PORTB, które można znaleźć w więcej niż jednej jednostce kompilacji (zakładając, że kod ma więcej niż jedną). p>
Używa specjalnej (nieprzenośnej) składni do określenia "lokalizacji" (lub wartości numerycznej etykiety, która jest zwykle adresem) PORTB. Tak więc linker otrzymuje adres i nie musi go szukać. Gdybyś miał dwie jednostki kompilacji używające tej linii, i tak każda z nich wskazywałaby to samo miejsce. Nie ma więc potrzeby oznaczania go tutaj „extern”.
Gdyby użyli „extern”, mogłoby to stanowić problem. Konsolidator byłby wtedy w stanie zobaczyć (i próbowałby dopasować) wiele odniesień do PORTB znalezionych w wielu kompilacjach. Jeśli wszystkie z nich określają taki adres, a adresy z jakiegoś powodu NIE są takie same [błąd?], To co ma zrobić? Skarżyć się? Lub? (Technicznie rzecz biorąc, z „extern” zasadą kciuka byłoby, że tylko jednostka kompilacji ONE określałaby wartość, a pozostałe nie powinny).
Po prostu łatwiej jest oznaczyć go jako „statyczny”, dzięki czemu linker nie będzie martwił się konfliktami i po prostu obarczaj winą wszelkie błędy związane z błędnie dopasowanymi adresami tego, kto zmienił adres na taki, którym nie powinien. p>
Tak czy inaczej, zmienna jest traktowana jako posiadająca „statyczny okres istnienia”. (I „niestabilny”.)
Deklaracja nie jest definicją , ale wszystkie definicje są deklaracjami
W języku C definicja tworzy obiekt. To również deklaruje. Jednak deklaracja nie zwykle (zobacz notatka poniżej) tworzy obiekt.
Poniżej znajdują się definicje i deklaracje:
static int a;
static int a = 7;
extern int b = 5;
extern int f () {return 10; }
Poniższe informacje nie są definicjami, a jedynie deklaracjami:
extern int b;
extern int f ();
Zauważ, że deklaracje nie tworzą rzeczywistego obiektu. Deklarują tylko szczegóły na jego temat, których kompilator może następnie użyć, aby pomóc w wygenerowaniu poprawnego kodu oraz w razie potrzeby dostarczać ostrzeżenia i komunikaty o błędach.
-
Powyżej, radzę powiedzieć „zwykle”.W niektórych przypadkach deklaracja może utworzyć obiekt i dlatego jest promowana do definicji przez konsolidator (nigdy przez kompilator). Więc nawet w tym rzadkim przypadku kompilator C nadal uważa, że deklaracja jest tylko deklaracją.Jest to faza łącznika, która dokonuje niezbędnych promocji jakiejś deklaracji.Miej to na uwadze.
Jeśli w powyższych przykładach okaże się, że istnieją deklaracje tylko dla "extern int b;"we wszystkich połączonych jednostkach kompilacji odpowiedzialność za utworzenie definicji ponosi konsolidator.Należy pamiętać, że jest to zdarzenie czasu łącza.Kompilator jest całkowicie nieświadomy podczas kompilacji.Można to określić tylko w czasie łącza, jeśli deklaracja tego typu jest najczęściej promowana.
Kompilator jest świadomy, że „static int a;”nie mogą być promowane przez linkera w czasie łączenia, więc w rzeczywistości jest to definicja w czasie kompilacji .