C ++ - Semantik von `static const` vs` const`

149

Was sind speziell in C ++ die semantischen Unterschiede zwischen zum Beispiel:

static const int x = 0 ;

und

const int x = 0 ;

sowohl staticals Verknüpfungs- als auch als Speicherklassenspezifizierer (dh innerhalb und außerhalb einer Funktion).

Clifford
quelle
7
staticist wahrscheinlich das am meisten überladene Schlüsselwort in C ++. Die Bedeutung Ihres Codes variiert stark, je nachdem, ob er sich im Namespace-Bereich, im Klassenbereich oder im Funktionsbereich befindet. Vielleicht möchten Sie das klarstellen.
sbi
1
@sbi: Ich dachte ich hätte es schon getan. Funktionsumfang (wo es sich um einen Speicherklassenspezifizierer handelt) und Dateibereich (wo es sich um einen Verknüpfungsspezifizierer handelt). Klassenmitglieder und Variablen mit Namespace-Bereich sind für mich in Bezug auf diese Frage nicht von Belang. Wenn jedoch jemand der Meinung ist, dass es eine interessante Unterscheidung gibt, können Sie diese auch behandeln.
Clifford
@ Clifford: Es tut mir leid, dass ich diese letzten Worte übersehen habe. Dies ist jedoch ein Missverständnis auf Ihrer Seite offenbart: In C ++, Dateiumfang ist Namespacebereich. Wenn Sie etwas außerhalb eines Namespace deklarieren, gehört es einfach zum globalen Namespace (und ist über ein Präfix ::ohne Bezeichner zugänglich ). Mir sind keine bedeutenden Unterschiede zwischen dem globalen Namespace und einem darin verschachtelten Namespace bekannt. Es gibt sicherlich keine in Bezug auf staticObjekte.
sbi
1
Die Verknüpfung unterscheidet sich von der Sichtbarkeit . Wenn Sie sie austauschbar verwenden, werden Sie die Personen, mit denen Sie sprechen, und wahrscheinlich auch sich selbst verwirren.
Ben Voigt
1
@Ben, @sbi: Ich wollte nicht vorschlagen, dass der Dateibereich und die statische Verknüpfung identisch sind, sondern lediglich, dass die statische Verknüpfung den Dateibereich impliziert . In diesem Sinne ist Umfang (oder Sichtbarkeit) ein Attribut der statischen und externen Verknüpfung, kein Synonym für beides. Ich bin der Meinung, dass die ursprüngliche Frage klar und gut formuliert bleibt und dass wir lediglich die Kommentare diskutieren, die als Antwort auf die etwas herablassende Bemerkung von sbi abgegeben wurden. Wir diskutieren hier eher die ungenaue Semantik des Englischen als mein Verständnis, also denke ich, dass wir aufhören können.
Clifford

Antworten:

128

Im Dateibereich kein Unterschied in C ++. constmacht die interne Verknüpfung zum Standard und alle globalen Variablen haben eine statische Lebensdauer. Die erste Variante hat jedoch das gleiche Verhalten in C, so dass dies ein guter Grund sein kann, es zu verwenden.

Innerhalb einer Funktion kann die zweite Version aus Parametern berechnet werden. In C oder C ++ muss es keine Kompilierungszeitkonstante sein, wie es einige andere Sprachen erfordern.

Innerhalb einer Klasse im Grunde das Gleiche wie für Funktionen. Ein Instanzwert constkann in der ctor-initializer-Liste berechnet werden . A static constwird während der Startinitialisierung gesetzt und bleibt für den Rest des Programms unverändert. (Hinweis: Der Code für staticMitglieder sieht etwas anders aus, da Deklaration und Initialisierung getrennt sind.)

Denken Sie daran, in C ++, constMittel schreibgeschützt , nicht konstant . Wenn Sie einen Zeiger auf haben, können constandere Teile des Programms den Wert ändern, während Sie nicht suchen. Wenn die Variable mit definiert wurde const, kann niemand sie nach der Initialisierung ändern, aber die Initialisierung kann immer noch beliebig komplex sein.

Ben Voigt
quelle
1
Gibt es etwas, das als Dateibereich bezeichnet wird? Ich habe gerade $ 3.3 überprüft und ich denke, der nächste ist der 'Namespace-Bereich'. Ist mein Verständnis richtig? Der C ++ 03 Standard erwähnt den Dateibereich nur in den Anhängen
Chubsdad
2
Ich würde vorschlagen, dass der Dateibereich eher ein Artefakt des Linkers als des Compilers ist und daher im Sprachstandard möglicherweise nicht viel Beachtung findet. Streng genommen handelt es sich wahrscheinlich um "Compilation Unit Scope".
Clifford
8
+1 für den Ausdruck "const bedeutet schreibgeschützt, nicht konstant", dh "Compiler, wenn Sie jemanden sehen, der versucht, dieses const-Ding zu modifizieren, bellen Sie sehr laut." Dies ist der Grund, warum etwas gleichzeitig konstant und flüchtig sein kann.
Dan
5
Es ist mehr "Compiler, wenn Sie sehen, dass ich versuche, diese Konstante zu ändern (oder jemand anderem die Erlaubnis dazu zu geben)", bellen Sie sehr laut. In den meisten Fällen constgilt für eine Ansicht der Variablen und nicht für die Variable selbst, dass eine andere Person constdieselbe Variable nicht anzeigen kann, und der Compiler ist ziemlich still, wenn er sie ändert.
Ben Voigt
1
@Ben: Um ganz klar zu sein, C ++ 0x entfernt diese spezielle Verwendung von nicht const, aber die neue constexprkann stattdessen verwendet werden (und auch in anderen Szenarien). Tatsächlich erweitert der C ++ 0x-Standard die Verwendung constin diesem Szenario auch auf nicht integrale "Literaltypen". Ich denke, ich würde es vorziehen, constexprfür diese Fälle zu verwenden, da Sie die Abwärtskompatibilität mit Pre-C ++ 0x-Compilern sowieso brechen würden.
Michael Burr
4

C ++ 17-Standardentwurf constimpliziert den staticDateibereich

Dies ist das Zitat für das, was unter https://stackoverflow.com/a/3709257/895245 erwähnt wurde

C ++ 17 n4659 Standardentwurf 6.5 "Programm und Verknüpfung":

3 Ein Name mit Namespace-Bereich (6.3.6) hat eine interne Verknüpfung, wenn es sich um den Namen von handelt

  • (3.1) - eine Variable, Funktion oder Funktionsvorlage, die explizit als statisch deklariert ist; oder,
  • (3.2) - eine nicht inline Variable vom nichtflüchtigen const-qualifizierten Typ, die weder explizit extern deklariert noch zuvor als extern verknüpft deklariert wurde; oder
  • (3.3) - ein Datenmitglied einer anonymen Gewerkschaft.

Anhang C (informativ) Kompatibilität, C.1.2 Abschnitt 6: "Grundbegriffe" gibt die Begründung, warum dies von C geändert wurde:

6.5 [auch 10.1.7]

Änderung: Ein Name des Dateibereichs, der explizit als const deklariert und nicht explizit als extern deklariert wird, hat eine interne Verknüpfung, während er in C eine externe Verknüpfung hätte.

Begründung: Da const-Objekte während der Übersetzung in C ++ als Werte verwendet werden können, fordert diese Funktion Programmierer auf, für jedes const-Objekt einen expliziten Initialisierer bereitzustellen. Mit dieser Funktion kann der Benutzer const-Objekte in Quelldateien einfügen, die in mehr als einer Übersetzungseinheit enthalten sind.

Auswirkung auf das ursprüngliche Merkmal: Wechseln Sie zur Semantik eines genau definierten Merkmals.

Konvertierungsschwierigkeiten: Semantische Transformation.

Wie weit verbreitet: Selten.

Siehe auch: Warum impliziert const eine interne Verknüpfung in C ++, wenn dies in C nicht der Fall ist?

Was Sie wahrscheinlich stattdessen für Header tun möchten

Ausführlich erklärt unter: Was bedeutet 'const static' in C und C ++?

  • vor C ++ 17: externim Header Definition in der CPP-Datei
  • Post C ++ 17: Inline-Variable im Header
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
Vielen Dank, obwohl ich nicht denke, dass dies eine Chance in C ++ 17 im Vergleich zu C ++ 98 ist, und die Frage wurde 2010 gestellt. Außerdem befasst sich Ihre Antwort nur mit statisch als Verknüpfungsspezifizierer (im Namespace-Bereich). und die Frage, die speziell zur Semantik in verschiedenen Kontexten gestellt wurde.
Clifford
@ Clifford ja, definitiv älter als C ++ 17, nur faul, alle Standards zu lesen ;-) Klärt den Teil des Dateibereichs.
Ciro Santilli 法轮功 冠状 病 六四 事件 26