Ma zastosowania zarówno w C, jak i C ++.
Jak się domyślasz, static
część ogranicza swój zakres do tej jednostki kompilacji . Zapewnia również statyczną inicjalizację. const
po prostu mówi kompilatorowi, aby nie pozwalał nikomu go modyfikować. Ta zmienna jest umieszczana w segmencie danych lub bss w zależności od architektury i może znajdować się w pamięci oznaczonej jako tylko do odczytu.
To wszystko w jaki sposób C traktuje te zmienne (lub jak C ++ traktuje zmienne przestrzeni nazw). W C ++ oznaczony element członkowski static
jest współużytkowany przez wszystkie wystąpienia danej klasy. To, czy jest prywatna, czy nie, nie wpływa na fakt, że jedna zmienna jest współdzielona przez wiele instancji. Obecność const
tam ostrzeże Cię, jeśli jakikolwiek kod będzie próbował to zmodyfikować.
Gdyby była ściśle prywatna, każda instancja klasy otrzymałaby swoją własną wersję (niezależnie od optymalizatora).
Wiele osób dało odpowiedź podstawowe, ale nikt nie zauważył, że w C ++
const
domyślnych abystatic
nanamespace
poziomie (i niektórzy dali błędne informacje). Zobacz standard C ++ 98 w sekcji 3.5.3.Najpierw trochę tła:
Jednostka tłumacząca: plik źródłowy po preprocesorze (rekurencyjnie) zawierał wszystkie pliki dołączane.
Powiązanie statyczne: symbol jest dostępny tylko w jednostce tłumaczeniowej.
Powiązanie zewnętrzne: symbol jest dostępny w innych jednostkach tłumaczeniowych.
Na
namespace
poziomieObejmuje to globalną przestrzeń nazw, czyli zmienne globalne .
Na poziomie funkcji
static
oznacza, że wartość jest utrzymywana między wywołaniami funkcji.Semantyka
static
zmiennych funkcyjnych jest podobna do zmiennych globalnych, ponieważ znajdują się one w segmencie danych programu (a nie na stosie lub stercie). Zobacz to pytanie, aby uzyskać więcej informacji na temat czasustatic
życia zmiennych.Na
class
poziomiestatic
oznacza, że wartość jest wspólna dla wszystkich instancji klasy iconst
oznacza, że się nie zmienia.źródło
const int *foo(int x) {const int b=x;return &b};
niżconst int *foo(int x) {static const int b=x;return &b};
const
tylko na temat sugerowaniastatic
w tym drugim.const
deklaracja implikuje równieżstatic
tam? Tak jak w przypadku odrzuceniaconst
i zmodyfikowania wartości, wszystkie wartości zostaną zmodyfikowane?const
nie oznacza statyczności na poziomie funkcji, co byłoby koszmarem współbieżności (const! = Stałe wyrażenie), wszystko na poziomie funkcji jest niejawneauto
. Ponieważ to pytanie jest również oznaczone jako [c], powinienem wspomnieć, że poziom globalnyconst int
znajduje się niejawnieextern
w C. Jednak reguły, które tu masz, doskonale opisują C ++.static
wskazuje, że zmienna ma statyczny czas trwania (istnieje tylko jedna kopia, która trwa od początku do końca programu) i ma wewnętrzne / statyczne powiązanie, jeśli nie określono inaczej (jest to nadpisywane przez funkcję połączenie dla lokalnych zmiennych statycznych lub połączenie klasy dla elementów statycznych). Główne różnice dotyczą tego, co to oznacza w każdej sytuacji, w którejstatic
jest to ważne.Ta linia kodu może faktycznie pojawić się w kilku różnych kontekstach i chociaż zachowuje się mniej więcej tak samo, istnieją niewielkie różnice.
Zakres przestrzeni nazw
„
i
” będzie widoczny w każdej jednostce tłumaczeniowej zawierającej nagłówek. Jednak jeśli faktycznie nie użyjesz adresu obiektu (na przykład. „&i
”), Jestem prawie pewien, że kompilator potraktuje „i
” po prostu jako typ bezpieczny0
. Tam, gdzie dwie kolejne jednostki tłumaczeniowe przyjmą znak „&i
”, adres będzie inny dla każdej jednostki tłumaczeniowej.„
i
” ma wewnętrzne powiązanie, więc nie można się do niego odwoływać spoza tej jednostki tłumaczeniowej. Jednak ponownie, jeśli nie użyjesz jego adresu, najprawdopodobniej będzie traktowany jako bezpieczny dla typów0
.Warto zwrócić uwagę, że następująca deklaracja:
jest dokładnie taki sam jak
static const int i = 0
. Zmienna w przestrzeni nazw zadeklarowana ziconst
nie zadeklarowana jawnie za pomocąextern
jest niejawnie statyczna. Jeśli się nad tym zastanowić, intencją komitetu C ++ było zezwolenieconst
na deklarowanie zmiennych w plikach nagłówkowych bez konieczności używaniastatic
słowa kluczowego, aby uniknąć zerwania ODR.Zakres zajęć
W powyższym przykładzie norma wyraźnie określa, że „
i
” nie musi być definiowane, jeśli jego adres nie jest wymagany. Innymi słowy, jeśli używasz tylko „i
” jako bezpiecznego 0, kompilator nie zdefiniuje go. Jedną różnicą między wersjami klasy i przestrzeni nazw jest to, że adres „i
” (jeśli jest używany w dwóch lub więcej jednostkach tłumaczeniowych) będzie taki sam dla elementu klasy. Tam, gdzie używany jest adres, musisz mieć jego definicję:źródło
To niewielka optymalizacja przestrzeni.
Kiedy powiesz
Nie definiujesz stałej, ale tworzysz zmienną tylko do odczytu. Kompilator jest wystarczająco inteligentny, aby użyć 42, ilekroć zobaczy foo, ale przydzieli mu również miejsce w zainicjowanym obszarze danych. Dzieje się tak, ponieważ zgodnie z definicją foo ma zewnętrzne połączenie. Inna jednostka kompilacji może powiedzieć:
extern const int foo;
Aby uzyskać dostęp do jego wartości. To nie jest dobra praktyka, ponieważ ta jednostka kompilacji nie ma pojęcia, jaka jest wartość foo. Po prostu wie, że jest to const int i musi ponownie załadować wartość z pamięci za każdym razem, gdy jest używana.
Teraz, deklarując, że jest statyczny:
Kompilator może przeprowadzić swoją zwykłą optymalizację, ale może również powiedzieć „hej, nikt poza tą jednostką kompilacji nie widzi foo i wiem, że zawsze jest to 42, więc nie ma potrzeby przydzielania na to miejsca”.
Powinienem również zauważyć, że w C ++ preferowanym sposobem zapobiegania ucieczce nazw z bieżącej jednostki kompilacji jest użycie anonimowej przestrzeni nazw:
źródło
Brakuje „int”. Powinno być:
W C i C ++ deklaruje stałą całkowitą z zakresem pliku lokalnego o wartości 42.
Dlaczego 42? Jeśli jeszcze nie wiesz (i trudno uwierzyć, że nie), jest to odniesienie do odpowiedzi na życie, wszechświat i wszystko .
źródło
W C ++
jest preferowanym sposobem definiowania i używania stałych. Używam raczej tego niż
ponieważ nie podważa systemu bezpieczeństwa typu.
źródło
Do wszystkich świetnych odpowiedzi chcę dodać mały szczegół:
Jeśli piszesz wtyczki (np. Biblioteki DLL lub .so, które mają być ładowane przez system CAD), statyczność jest ratunkiem, który pozwala uniknąć kolizji nazw, takich jak ta:
Co gorsza: krok 3 może zachowywać się inaczej w zależności od optymalizacji kompilatora, mechanizmu ładowania wtyczki itp.
Miałem ten problem raz z dwiema funkcjami pomocniczymi (ta sama nazwa, inne zachowanie) w dwóch wtyczkach. Zadeklarowanie ich jako statyczne rozwiązało problem.
źródło
Zgodnie ze specyfikacją C99 / GNU99:
static
jest specyfikatorem klasy pamięci
obiekty o zasięgu na poziomie pliku domyślnie mają połączenie zewnętrzne
const
jest kwalifikatorem typu (jest częścią typu)
słowo kluczowe stosowane do bezpośredniego lewego wystąpienia - tj
MyObj const * myVar;
- niekwalifikowany wskaźnik do stałego kwalifikowanego typu obiektuMyObj * const myVar;
- const kwalifikowany wskaźnik do niekwalifikowanego typu obiektuUżycie skrajnie lewe - stosowane do typu obiektu, a nie do zmiennej
const MyObj * myVar;
- niekwalifikowany wskaźnik do stałego kwalifikowanego typu obiektuA ZATEM:
static NSString * const myVar;
- stały wskaźnik do niezmiennego łańcucha z wewnętrznym połączeniem.Brak
static
słowa kluczowego spowoduje, że nazwa zmiennej stanie się globalna i może prowadzić do konfliktów nazw w aplikacji.źródło
inline
Zmienne C ++ 17Jeśli wpisałeś w Google „C ++ const static”, jest bardzo prawdopodobne, że naprawdę chcesz użyć zmiennych wbudowanych w C ++ 17 .
Ta niesamowita funkcja C ++ 17 pozwala nam:
constexpr
: Jak zadeklarować extern constexpr?main.cpp
notmain.hpp
notmain.cpp
Skompiluj i uruchom:
GitHub upstream .
Zobacz także: Jak działają zmienne wbudowane?
Standard C ++ dotyczący zmiennych wbudowanych
Standard C ++ gwarantuje, że adresy będą takie same. C ++ 17 N4659 standardowa wersja robocza 10.1.6 „Specyfikator wbudowany”:
cppreference https://en.cppreference.com/w/cpp/language/inline wyjaśnia, że jeśli
static
nie jest podane, ma link zewnętrzny.Implementacja zmiennych inline GCC
Możemy obserwować, jak jest realizowany za pomocą:
który zawiera:
i
man nm
mówi ou
:więc widzimy, że jest do tego dedykowane rozszerzenie ELF.
Przed C ++ 17:
extern const
Przed C ++ 17, a także w C, możemy osiągnąć bardzo podobny efekt za pomocą
extern const
, co doprowadzi do użycia jednej lokalizacji pamięci.Wady
inline
to:constexpr
tą techniką,inline
pozwala tylko na to: Jak zadeklarować constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub upstream .
Alternatywy tylko dla nagłówków przed C ++ 17
Nie są one tak dobre, jak
extern
rozwiązanie, ale działają i zajmują tylko jedną lokalizację w pamięci:constexpr
Funkcja, ponieważconstexpr
zakładainline
iinline
pozwala (siły) definicja pojawiać się na każdej jednostki tłumaczeniowej :i założę się, że każdy przyzwoity kompilator wbuduje wywołanie.
Możesz również użyć zmiennej statycznej
const
lub,constexpr
jak w:ale nie możesz zrobić takich rzeczy, jak pobranie jego adresu, w przeciwnym razie zostanie on użyty odr, zobacz także: Definiowanie stałych elementów danych constexpr
do
W C sytuacja jest taka sama, jak w C ++ przed C ++ 17, przesłałem przykład pod adresem: Co oznacza „statyczny” w C?
Jedyną różnicą jest to, że w C ++
const
implikuje tostatic
dla globals, ale nie w C: C ++ semantyka `static const` vs` const`Jakikolwiek sposób, aby w pełni go wbudować?
DO ZROBIENIA: czy istnieje sposób na pełne wstawienie zmiennej bez użycia jakiejkolwiek pamięci?
Podobnie jak robi to preprocesor.
Wymagałoby to w jakiś sposób:
Związane z:
Testowany w Ubuntu 18.10, GCC 8.2.0.
źródło
Tak, ukrywa zmienną w module przed innymi modułami. W C ++ używam go, gdy nie chcę / nie muszę zmieniać pliku .h, co spowoduje niepotrzebną przebudowę innych plików. Ponadto stawiam najpierw statyczny:
Ponadto, w zależności od jego użycia, kompilator nawet nie przydzieli dla niego pamięci i po prostu „wstawi” wartość, w której jest używany. Bez statycznego kompilator nie może założyć, że nie jest używany w innym miejscu i nie może być wbudowany.
źródło
Jest to między innymi stała globalna widoczna / dostępna tylko w module kompilacji (plik .cpp). BTW używanie do tego celu statycznego jest przestarzałe. Lepiej użyj anonimowej przestrzeni nazw i wyliczenia:
źródło
enum
w tym kontekście. Możesz rozwinąć temat? Takieenums
są zwykle używane tylko po to, aby zapobiec przydzielaniu przez kompilator jakiejkolwiek przestrzeni na wartość (chociaż współczesne kompilatory nie potrzebują do tego tegoenum
hackowania) i aby zapobiec tworzeniu wskaźników do wartości.Ustawienie go jako prywatnego nadal oznaczałoby, że pojawia się w nagłówku. Zwykle używam „najsłabszego” sposobu, który działa. Zobacz ten klasyczny artykuł Scotta Meyersa: http://www.ddj.com/cpp/184401197 (dotyczy funkcji, ale można go również zastosować tutaj).
źródło