Semantyka C ++ „statycznej stałej” i „stałej”

149

W szczególności w C ++, jakie są semantyczne różnice między na przykład:

static const int x = 0 ;

i

const int x = 0 ;

zarówno staticjako łącznik, jak i specyfikator klasy pamięci (tj. wewnątrz i na zewnątrz funkcji).

Clifford
źródło
7
staticjest prawdopodobnie najbardziej przeciążonym słowem kluczowym w C ++. Znaczenie twojego kodu różni się znacznie w zależności od tego, czy znajduje się w zakresie przestrzeni nazw, w zakresie klasy, czy w zakresie funkcji. Możesz to wyjaśnić.
sbi
1
@sbi: Myślałem, że już to zrobiłem. Zakres funkcji (gdzie jest to specyfikator klasy pamięci) i zasięg pliku (gdzie jest to specyfikator powiązania). Członkowie klas i zmienne w zakresie przestrzeni nazw nie są dla mnie szczególnie istotne w związku z tym pytaniem, chociaż jeśli ktokolwiek uważa, że ​​istnieje interesujące rozróżnienie, nie krępuj się też go omówić.
Clifford,
@Clifford: Przepraszam, że przeoczyłem te ostatnie słowa. Jednak ujawniło to nieporozumienie z Twojej strony: w C ++ zakres pliku jest zakresem przestrzeni nazw. Jeśli zadeklarujesz cokolwiek poza jakąkolwiek przestrzenią nazw, będzie to po prostu należeć do globalnej przestrzeni nazw (i jest dostępne poprzez prefiks ::bez identyfikatora z przodu). Nie znam żadnych znaczących różnic między globalną przestrzenią nazw a jakąkolwiek zagnieżdżoną w niej przestrzenią nazw. Z pewnością nie ma żadnych dotyczących staticprzedmiotów.
sbi
1
powiązanie różni się od widoczności , używając ich zamiennie, zmylisz ludzi, z którymi rozmawiasz, a prawdopodobnie także siebie.
Ben Voigt,
1
@Ben, @sbi: Nie zamierzałem sugerować, że zakres plików i łączenie statyczne były takie same, po prostu łączenie statyczne implikuje zakres plików. W tym sensie zasięg (lub widoczność) jest atrybutem powiązania statycznego i zewnętrznego, a nie synonimem żadnego z nich. Wydaje mi się, że pierwotne pytanie pozostaje jasne i dobrze sformułowane, i że omawiamy jedynie komentarze poczynione w odpowiedzi na nieco protekcjonalną uwagę sbi. Omawiamy tutaj nieprecyzyjną semantykę języka angielskiego, a nie moje rozumienie, więc myślę, że możemy przestać.
Clifford,

Odpowiedzi:

128

W zakresie pliku nie ma różnicy w C ++. constustawia łączenie wewnętrzne jako domyślne, a wszystkie zmienne globalne mają statyczny okres istnienia. Ale pierwszy wariant zachowuje się tak samo w C, więc może to być dobry powód, aby go użyć.

W ramach funkcji drugą wersję można obliczyć na podstawie parametrów. W C lub C ++ nie musi to być stała czasu kompilacji, jak wymagają tego niektóre inne języki.

W klasie zasadniczo to samo, co w przypadku funkcji. constWartość wystąpienia można obliczyć na liście ctor-initializer-list . A static constjest ustawiane podczas inicjalizacji uruchamiania i pozostaje niezmienione przez resztę programu. (Uwaga: kod staticczłonków wygląda trochę inaczej, ponieważ deklaracja i inicjalizacja są oddzielone).

Pamiętaj, że w C ++ constoznacza tylko do odczytu , a nie stałą . Jeśli masz wskaźnik do, constinne części programu mogą zmienić wartość, gdy nie patrzysz. Jeśli zmienna została zdefiniowana za pomocą const, to nikt nie może jej zmienić po inicjalizacji, ale inicjalizacja może być dowolnie złożona.

Ben Voigt
źródło
1
Czy istnieje coś, co nazywa się zakresem pliku? Właśnie sprawdzałem 3,3 USD i myślę, że najbliższy jest „zakres przestrzeni nazw”. Czy moje zrozumienie jest prawidłowe? Standard C ++ 03 wspomina o zakresie plików tylko w Dodatkach
Chubsdad
2
Sugerowałbym, że zakres plików jest raczej artefaktem konsolidatora niż kompilatora, więc standard języka może nie zwracać na nie większej uwagi. Ściśle mówiąc, jest to prawdopodobnie „zakres jednostki kompilacji”.
Clifford
8
+1 dla frazy „const oznacza tylko do odczytu, a nie stała”, tj. „Kompilator, jeśli zobaczysz, że ktoś próbuje zmodyfikować tę stałą, szczekaj bardzo głośno”. To jest powód, dla którego coś może być jednocześnie stałe i niestabilne.
Dan,
5
To bardziej "Kompilator, jeśli widzisz, jak próbuję zmodyfikować tę stałą (lub dać komuś pozwolenie na to)", szczekaj bardzo głośno. W większości constprzypadków dotyczy widoku zmiennej, a nie samej zmiennej, ktoś inny może nie mieć constwidoku tej samej zmiennej, a kompilator będzie milczał, gdy ją modyfikuje.
Ben Voigt,
1
@Ben: Żeby było jasne, C ++ 0x nie usuwa tego konkretnego zastosowania const, ale constexprzamiast tego można użyć nowego (a także w innych scenariuszach). W rzeczywistości standard C ++ 0x rozszerza możliwości użycia constw tym scenariuszu również na niecałkowite „typy literałów”. Myślę, że wolałbym używać constexprw tych przypadkach, ponieważ i tak złamałbyś wsteczną kompatybilność z kompilatorami pre-C ++ 0x.
Michael Burr
4

Standardowy szkic C ++ 17 na constimplikacjachstatic w zakresie pliku

Oto cytat z tego, co wspomniano pod adresem : https://stackoverflow.com/a/3709257/895245

C ++ 17 n4659 standardowa wersja robocza 6.5 „Program i powiązanie”:

3 Nazwa mająca zasięg przestrzeni nazw (6.3.6) ma łącze wewnętrzne, jeśli jest nazwą

  • (3.1) - zmienna, funkcja lub szablon funkcji, który jest jawnie zadeklarowany jako statyczny; lub,
  • (3.2) - nieliniowa zmienna o nieulotnym typie z klasyfikacją const, która nie jest ani jawnie zadeklarowana jako zewnętrzna, ani wcześniej zadeklarowana jako posiadająca łącze zewnętrzne; lub
  • (3.3) - członek anonimowego związku.

Załącznik C (informacyjny) Zgodność, C.1.2 Rozdział 6: „podstawowe pojęcia” podaje uzasadnienie, dlaczego zostało to zmienione z C:

6.5 [także 10.1.7]

Zmiana: nazwa zakresu pliku, która jest jawnie zadeklarowana jako const, a nie jawnie zadeklarowana jako extern, ma wewnętrzne połączenie, podczas gdy w C miałaby połączenie zewnętrzne.

Uzasadnienie: Ponieważ obiekty const mogą być używane jako wartości podczas tłumaczenia w C ++, ta funkcja zachęca programistów do dostarczenia jawnego inicjatora dla każdego obiektu const. Ta funkcja umożliwia użytkownikowi umieszczanie obiektów stałych w plikach źródłowych, które są zawarte w więcej niż jednej jednostce tłumaczenia.

Wpływ na oryginalną cechę: zmiana na semantykę dobrze zdefiniowanej cechy.

Trudność konwersji: transformacja semantyczna.

Jak szeroko stosowany: rzadko.

Zobacz także: Dlaczego const implikuje wewnętrzne powiązanie w C ++, a nie w C?

Co prawdopodobnie chcesz zrobić zamiast nagłówków

Szczegółowe wyjaśnienie w: Co oznacza „const static” w językach C i C ++?

  • przed C ++ 17: extern w nagłówku, definicja w pliku cpp
  • po C ++ 17: zmienna inline w nagłówku
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
Dzięki, chociaż nie sądzę, żeby to była szansa w C ++ 17 w porównaniu nawet z C ++ 98, a pytanie zostało zadane w 2010 roku. Co więcej, twoja odpowiedź dotyczy tylko statycznego jako specyfikatora powiązania (w zakresie przestrzeni nazw) i pytanie zadane konkretnie na temat semantyki w różnych kontekstach.
Clifford
@Clifford tak, zdecydowanie starszy niż C ++ 17, po prostu leniwy, aby czytać wszystkie standardy ;-) Wyjaśni część dotyczącą zakresu plików.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功