Es wird sowohl in C als auch in C ++ verwendet.
Wie Sie vermutet haben, beschränkt der static
Teil seinen Umfang auf diese Kompilierungseinheit . Es ermöglicht auch eine statische Initialisierung. const
weist den Compiler lediglich an, sich von niemandem ändern zu lassen. Diese Variable wird je nach Architektur entweder in das Daten- oder das BSS-Segment eingefügt und befindet sich möglicherweise im Speicher, der als schreibgeschützt markiert ist.
So behandelt C diese Variablen (oder wie C ++ Namespace-Variablen behandelt). In C ++ wird ein markiertes Mitglied static
von allen Instanzen einer bestimmten Klasse gemeinsam genutzt. Ob es privat ist oder nicht, hat keinen Einfluss darauf, dass eine Variable von mehreren Instanzen gemeinsam genutzt wird. Wenn Sie const
dort sind, werden Sie gewarnt, wenn ein Code versuchen würde, dies zu ändern.
Wenn es streng privat wäre, würde jede Instanz der Klasse eine eigene Version erhalten (trotz Optimierer).
Viele Leute gaben die grundlegende Antwort, aber niemand wies darauf hin, dass in C ++
const
standardmäßigstatic
aufnamespace
Ebene (und einige gaben falsche Informationen). Siehe den C ++ 98-Standardabschnitt 3.5.3.Zunächst einige Hintergrundinformationen:
Übersetzungseinheit: Eine Quelldatei nach dem Vorprozessor (rekursiv) enthielt alle Include-Dateien.
Statische Verknüpfung: Ein Symbol ist nur innerhalb seiner Übersetzungseinheit verfügbar.
Externe Verknüpfung: Ein Symbol ist von anderen Übersetzungseinheiten erhältlich.
Auf der
namespace
EbeneDies schließt den globalen Namespace, auch bekannt als globale Variablen, ein .
Auf Funktionsebene
static
bedeutet, dass der Wert zwischen Funktionsaufrufen beibehalten wird.Die Semantik von Funktionsvariablen
static
ähnelt globalen Variablen, da sie sich im Datensegment des Programms befinden (und nicht im Stapel oder im Heap). Weitere Informationen zur Lebensdauer von Variablen finden Sie in dieser Fragestatic
.Auf der
class
Ebenestatic
bedeutet, dass der Wert von allen Instanzen der Klasse gemeinsam genutzt wird undconst
sich nicht ändert.quelle
const int *foo(int x) {const int b=x;return &b};
Vergleichconst int *foo(int x) {static const int b=x;return &b};
const
hinzufügen, dass nurstatic
letzteres impliziert wird .const
Erklärung auchstatic
dort impliziert ? Wie in, wenn Sie wegwerfenconst
und den Wert ändern, werden alle Werte geändert?const
impliziert nicht statisch auf Funktionsebene, das wäre ein Albtraum der Parallelität (const! = Konstanter Ausdruck), alles auf Funktionsebene ist implizitauto
. Da diese Frage auch mit [c] markiert ist, sollte ich erwähnen, dass eine globale Ebeneconst int
implizitextern
in C enthalten ist. Die Regeln, die Sie hier haben, beschreiben C ++ jedoch perfekt.static
angegeben, dass die Variable eine statische Dauer hat (es ist nur eine Kopie vorhanden, die vom Anfang bis zum Ende des Programms dauert) und eine interne / statische Verknüpfung aufweist, sofern nicht anders angegeben (dies wird von der Funktion überschrieben) Verknüpfung für lokale statische Variablen oder Verknüpfung der Klasse für statische Elemente). Die Hauptunterschiede bestehen darin, was dies in jeder Situation impliziert, in der diesstatic
gültig ist.Diese Codezeile kann tatsächlich in verschiedenen Kontexten vorkommen, und obwohl sie sich ungefähr gleich verhält, gibt es kleine Unterschiede.
Namespace-Bereich
'
i
' wird in jeder Übersetzungseinheit angezeigt, die den Header enthält. Wenn Sie jedoch nicht tatsächlich die Adresse des Objekts verwenden (z. B. '&i
'), bin ich mir ziemlich sicher, dass der Compiler 'i
' einfach als typsicher behandelt0
. Wenn zwei weitere Übersetzungseinheiten das '&i
' annehmen , ist die Adresse für jede Übersetzungseinheit unterschiedlich.'
i
' hat eine interne Verknüpfung und kann daher nicht von außerhalb dieser Übersetzungseinheit referenziert werden. Wenn Sie jedoch nicht die Adresse verwenden, wird diese höchstwahrscheinlich als typsicher behandelt0
.Hervorzuheben ist die folgende Erklärung:
ist genau das gleiche wie
static const int i = 0
. Eine Variable in einem mitconst
und nicht explizit mit deklarierten Namespaceextern
ist implizit statisch. Wenn Sie darüber nachdenken, war es die Absicht des C ++ - Komitees, dieconst
Deklaration von Variablen in Header-Dateien zuzulassen , ohne immer dasstatic
Schlüsselwort zu benötigen , um eine Unterbrechung des ODR zu vermeiden.Klassenumfang
Im obigen Beispiel gibt der Standard explizit an, dass '
i
' nicht definiert werden muss, wenn seine Adresse nicht erforderlich ist. Mit anderen Worten, wenn Sie 'i
' nur als typsichere 0 verwenden, definiert der Compiler diese nicht. Ein Unterschied zwischen der Klassen- und der Namespace-Version besteht darin, dass die Adresse von 'i
' (wenn sie in zwei oder mehr Übersetzungseinheiten verwendet wird) für das Klassenmitglied gleich ist. Wo die Adresse verwendet wird, müssen Sie eine Definition dafür haben:quelle
Es ist eine kleine Raumoptimierung.
Wenn du sagst
Sie definieren keine Konstante, sondern erstellen eine schreibgeschützte Variable. Der Compiler ist intelligent genug, um 42 zu verwenden, wenn er foo sieht, aber er weist ihm auch Speicherplatz im initialisierten Datenbereich zu. Dies geschieht, weil foo wie definiert eine externe Verknüpfung hat. Eine andere Zusammenstellungseinheit kann sagen:
extern const int foo;
Zugriff auf seinen Wert erhalten. Das ist keine gute Praxis, da diese Kompilierungseinheit keine Ahnung hat, welchen Wert foo hat. Es weiß nur, dass es ein const int ist und muss den Wert bei jeder Verwendung aus dem Speicher neu laden.
Indem Sie nun erklären, dass es statisch ist:
Der Compiler kann seine übliche Optimierung durchführen, aber er kann auch sagen: "Hey, niemand außerhalb dieser Kompilierungseinheit kann foo sehen, und ich weiß, dass es immer 42 ist, so dass kein Platz dafür zugewiesen werden muss."
Ich sollte auch beachten, dass in C ++ die bevorzugte Methode, um zu verhindern, dass Namen der aktuellen Kompilierungseinheit entkommen, die Verwendung eines anonymen Namespace ist:
quelle
Es fehlt ein 'int'. Es sollte sein:
In C und C ++ deklariert es eine Ganzzahlkonstante mit dem lokalen Dateibereich des Werts 42.
Warum 42? Wenn Sie es noch nicht wissen (und es ist schwer zu glauben, dass Sie es nicht wissen), ist es ein Hinweis auf die Antwort auf das Leben, das Universum und alles .
quelle
In C ++
ist die bevorzugte Methode zum Definieren und Verwenden von Konstanten. Dh dies eher verwenden als
weil es das Typensicherheitssystem nicht untergräbt.
quelle
Zu all den tollen Antworten möchte ich ein kleines Detail hinzufügen:
Wenn Sie Plugins schreiben (z. B. DLLs oder .so-Bibliotheken, die von einem CAD-System geladen werden sollen), ist static ein Lebensretter, der Namenskollisionen wie diese vermeidet:
Noch schlimmer: Schritt 3 kann sich je nach Compileroptimierung, Plugin-Lademechanismus usw. unterschiedlich verhalten.
Ich hatte dieses Problem einmal mit zwei Hilfsfunktionen (gleicher Name, unterschiedliches Verhalten) in zwei Plugins. Die statische Erklärung löste das Problem.
quelle
Gemäß C99 / GNU99-Spezifikation:
static
ist ein Speicherklassenspezifizierer
Objekte mit Gültigkeitsbereich auf Dateiebene verfügen standardmäßig über eine externe Verknüpfung
const
ist ein Typqualifizierer (ist ein Teil des Typs)
Schlüsselwort, das auf die unmittelbare linke Instanz angewendet wird - dh
MyObj const * myVar;
- unqualifizierter Zeiger auf den qualifizierten Objekttyp constMyObj * const myVar;
- const qualifizierter Zeiger auf nicht qualifizierten ObjekttypVerwendung ganz links - wird auf den Objekttyp angewendet, nicht auf die Variable
const MyObj * myVar;
- unqualifizierter Zeiger auf den qualifizierten Objekttyp constSO:
static NSString * const myVar;
- konstanter Zeiger auf unveränderlichen String mit interner Verknüpfung.Das Fehlen des
static
Schlüsselworts macht den Variablennamen global und kann zu Namenskonflikten innerhalb der Anwendung führen.quelle
C ++ 17
inline
VariablenWenn Sie "C ++ const static" gegoogelt haben, ist es sehr wahrscheinlich, dass Sie wirklich C ++ 17-Inline-Variablen verwenden möchten .
Mit dieser fantastischen C ++ 17-Funktion können wir:
constexpr
: Wie deklariere ich constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Kompilieren und ausführen:
GitHub stromaufwärts .
Siehe auch: Wie funktionieren Inline-Variablen?
C ++ - Standard für Inline-Variablen
Der C ++ - Standard garantiert, dass die Adressen gleich sind. C ++ 17 N4659 Standardentwurf 10.1.6 "Der Inline-Spezifizierer":
cppreference https://en.cppreference.com/w/cpp/language/inline erklärt, dass, wenn
static
nicht angegeben, eine externe Verknüpfung besteht.Implementierung von GCC-Inline-Variablen
Wir können beobachten, wie es implementiert wird mit:
was beinhaltet:
und
man nm
sagt überu
:Wir sehen also, dass es dafür eine dedizierte ELF-Erweiterung gibt.
Pre-C ++ 17:
extern const
Vor C ++ 17 und in C können wir mit a einen sehr ähnlichen Effekt erzielen
extern const
, der dazu führt, dass ein einzelner Speicherort verwendet wird.Die Nachteile
inline
sind:constexpr
mit dieser Technik zu erstellen, sonderninline
erlaubt nur Folgendes : Wie deklariere ich constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub stromaufwärts .
Nur Header-Alternativen vor C ++ 17
Diese sind nicht so gut wie die
extern
Lösung, aber sie funktionieren und belegen nur einen einzigen Speicherort:Eine
constexpr
Funktion, weilconstexpr
impliziertinline
undinline
erlaubt (erzwingt), dass die Definition auf jeder Übersetzungseinheit erscheint :und ich wette, dass jeder anständige Compiler den Aufruf einbindet.
Sie können auch eine
const
oder eineconstexpr
statische Variable wie folgt verwenden:Sie können jedoch nicht die Adresse übernehmen oder sie wird odr-verwendet, siehe auch: Definieren von statischen constexpr-Datenelementen
C.
In C ist die Situation dieselbe wie in C ++ vor C ++ 17, ich habe ein Beispiel hochgeladen unter: Was bedeutet "statisch" in C?
Der einzige Unterschied besteht darin, dass in C ++ für Globale
const
impliziertstatic
wird, in C: C ++ jedoch nicht die Semantik von `static const` vs` const`Gibt es eine Möglichkeit, es vollständig zu integrieren?
TODO: Gibt es eine Möglichkeit, die Variable vollständig zu inline, ohne überhaupt Speicher zu verwenden?
Ähnlich wie der Präprozessor.
Dies würde irgendwie erfordern:
Verbunden:
Getestet in Ubuntu 18.10, GCC 8.2.0.
quelle
Ja, eine Variable in einem Modul wird vor anderen Modulen ausgeblendet. In C ++ verwende ich es, wenn ich keine .h-Datei ändern möchte / muss, die eine unnötige Neuerstellung anderer Dateien auslöst. Außerdem habe ich die Statik an die erste Stelle gesetzt:
Abhängig von seiner Verwendung weist der Compiler ihm nicht einmal Speicher zu und "inline" einfach den Wert, in dem er verwendet wird. Ohne die Statik kann der Compiler nicht davon ausgehen, dass er nicht anderweitig verwendet wird, und kann nicht inline.
quelle
Diese globale Konstante ist nur im Kompilierungsmodul (CPP-Datei) sichtbar / zugänglich. Übrigens ist die Verwendung von Static für diesen Zweck veraltet. Verwenden Sie besser einen anonymen Namespace und eine Aufzählung:
quelle
enum
in diesem Zusammenhang hat. Möchtest du das näher erläutern? Dieseenums
werden normalerweise nur verwendet, um zu verhindern, dass der Compiler Speicherplatz für den Wert reserviert (obwohl moderne Compiler diesenenum
Hack dafür nicht benötigen ) und um die Erstellung von Zeigern auf den Wert zu verhindern.Wenn Sie es privat machen, wird es immer noch in der Kopfzeile angezeigt. Ich neige dazu, "die schwächste" Art zu verwenden, die funktioniert. Siehe diesen klassischen Artikel von Scott Meyers: http://www.ddj.com/cpp/184401197 (es geht um Funktionen, kann aber auch hier angewendet werden).
quelle