Beim Umgestalten einiger habe #defines
ich in einer C ++ - Header-Datei ähnliche Deklarationen festgestellt:
static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;
Die Frage ist, welchen Unterschied wird die statische Aufladung machen, wenn überhaupt? Beachten Sie, dass das mehrfache Einfügen der Header aufgrund des klassischen #ifndef HEADER
#define HEADER
#endif
Tricks nicht möglich ist (falls dies wichtig ist).
Bedeutet statisch, dass nur eine Kopie VAL
erstellt wird, falls der Header in mehr als einer Quelldatei enthalten ist?
Antworten:
Die
static
bedeutet , dass es eine Kopie seinVAL
für jede Quelldatei erstellt es in enthalten ist. Es bedeutet aber auch , dass mehrere Einschlüsse in mehreren Definitionen von nicht dazu führen werden ,VAL
dass wird zur Verknüpfungszeit kollidieren. In Cstatic
müssten Sie ohne das sicherstellen, dass nur eine Quelldatei definiert ist,VAL
während die anderen Quelldateien dies deklarierenextern
. Normalerweise würde man dies tun, indem man es (möglicherweise mit einem Initialisierer) in einer Quelldatei definiert und dieextern
Deklaration in eine Header-Datei einfügt.static
Variablen auf globaler Ebene sind nur in ihrer eigenen Quelldatei sichtbar, unabhängig davon, ob sie über ein Include dort angekommen sind oder sich in der Hauptdatei befanden.Anmerkung des Herausgebers: In C ++ sind
const
Objekte, deren Deklaration weder das Schlüsselwortstatic
noch enthält,extern
implizitstatic
.quelle
Die Tags
static
undextern
für Variablen mit Dateibereich bestimmen, ob auf sie in anderen Übersetzungseinheiten (dh anderen.c
oder.cpp
Dateien) zugegriffen werden kann .static
gibt die variable interne Verknüpfung an und verbirgt sie vor anderen Übersetzungseinheiten. Variablen mit interner Verknüpfung können jedoch in mehreren Übersetzungseinheiten definiert werden.extern
gibt die Variable externe Verknüpfung an und macht sie für andere Übersetzungseinheiten sichtbar. In der Regel bedeutet dies, dass die Variable nur in einer Übersetzungseinheit definiert werden darf.Die Standardeinstellung (wenn Sie nicht angeben
static
oderextern
) ist einer der Bereiche, in denen sich C und C ++ unterscheiden.In C sind Variablen mit Dateibereich standardmäßig
extern
(externe Verknüpfung). Wenn Sie C verwenden,VAL
iststatic
undANOTHER_VAL
istextern
.In C ++ sind Variablen mit Dateibereich standardmäßig
static
(interne Verknüpfung), wenn dies der Fall istconst
, undextern
standardmäßig, wenn dies nicht der Fall ist . Wenn Sie mit C ++, beideVAL
undANOTHER_VAL
sindstatic
.Aus einem Entwurf der C-Spezifikation :
Aus einem Entwurf der C ++ - Spezifikation :
quelle
Die statische Aufladung bedeutet, dass Sie eine Kopie pro Datei erhalten, aber im Gegensatz zu anderen ist dies völlig legal. Sie können dies einfach mit einem kleinen Codebeispiel testen:
test.h:
test1.cpp:
test2.cpp:
Wenn Sie dies ausführen, erhalten Sie folgende Ausgabe:
quelle
TEST
warenconst
, wenn LTO es in eine einzige Speicherstelle optimieren würde. Aber-O3 -flto
von GCC 8.1 nicht.const
Variablen in C ++ haben eine interne Verknüpfung. Die Verwendungstatic
hat also keine Auswirkung.Ah
one.cpp
two.cpp
Wenn dies ein C-Programm wäre, würden Sie
i
(aufgrund einer externen Verknüpfung) den Fehler "Mehrfachdefinition" erhalten .quelle
static
hat den Effekt, dass es die Absicht und das Bewusstsein dessen, was man codiert, sauber signalisiert, was niemals eine schlechte Sache ist. Für mich ist das wievirtual
beim Überschreiben: Wir müssen nicht, aber die Dinge sehen viel intuitiver aus - und stimmen mit anderen Erklärungen überein -, wenn wir dies tun.Die statische Deklaration auf dieser Codeebene bedeutet, dass die Variable nur in der aktuellen Kompilierungseinheit sichtbar ist. Dies bedeutet, dass nur Code in diesem Modul diese Variable sieht.
Wenn Sie eine Header-Datei haben, die eine Variable als statisch deklariert, und dieser Header in mehreren C / CPP-Dateien enthalten ist, ist diese Variable für diese Module "lokal". Es gibt N Kopien dieser Variablen für die N Stellen, an denen der Header enthalten ist. Sie sind überhaupt nicht miteinander verwandt. Jeder Code in einer dieser Quelldateien verweist nur auf die Variable, die in diesem Modul deklariert ist.
In diesem speziellen Fall scheint das Schlüsselwort "statisch" keinen Vorteil zu bieten. Ich vermisse vielleicht etwas, aber es scheint keine Rolle zu spielen - ich habe noch nie so etwas gesehen.
Was das Inlining betrifft, ist die Variable in diesem Fall wahrscheinlich inlined, aber das liegt nur daran, dass sie als const deklariert ist. Der Compiler könnte eher auf Inline - Modul statischen Variablen, aber das ist abhängig von der Situation und der Code kompiliert wird. Es gibt keine Garantie dafür, dass der Compiler 'statics' inline.
quelle
const
desstatic
implizit und damit optional. Die Konsequenz ist, dass es keine Anfälligkeit für Mehrfachdefinitionsfehler gibt, wie Mike F. behauptete.Das C-Buch (kostenlos online) enthält ein Kapitel über Verknüpfungen, in dem die Bedeutung von "statisch" ausführlicher erläutert wird (obwohl die richtige Antwort bereits in anderen Kommentaren angegeben ist): http://publications.gbdirect.co.uk/c_book /chapter4/linkage.html
quelle
Um die Frage zu beantworten: "Bedeutet statisch, dass nur eine Kopie von VAL erstellt wird, falls der Header in mehr als einer Quelldatei enthalten ist?" ...
NEIN . VAL wird in jeder Datei, die den Header enthält, immer separat definiert.
Die Standards für C und C ++ verursachen in diesem Fall einen Unterschied.
Beachten Sie, dass moderne Linker sich möglicherweise über ANOTHER_VAL beschweren, wenn der Header in verschiedenen Dateien enthalten ist (derselbe globale Name wurde zweimal definiert), und sich definitiv beschweren würden, wenn ANOTHER_VAL mit einem anderen Wert in einer anderen Datei initialisiert wurde
Sie müssen auch die Tatsache berücksichtigen, dass beide Variablen als const bezeichnet werden. Im Idealfall würde der Compiler diese Variablen immer inline verwenden und keinen Speicher für sie einschließen. Es gibt eine ganze Reihe von Gründen, warum Speicher zugewiesen werden kann. Eine, an die ich denken kann ...
quelle
Angenommen, diese Deklarationen haben einen globalen Geltungsbereich (dh sind keine Mitgliedsvariablen), dann:
statisch bedeutet "interne Verknüpfung". In diesem Fall kann dies vom Compiler optimiert / eingefügt werden , da es als const deklariert ist . Wenn Sie die const weglassen muss der Compiler Speicher in jeder Kompilierungseinheit zuweisen.
Wenn Sie statisch weglassen, erfolgt die Verknüpfung standardmäßig extern . Auch hier wurden Sie durch die Konstanz gerettet - der Compiler kann die Nutzung optimieren / inline. Wenn Sie die Konstante löschen , wird zum Zeitpunkt der Verknüpfung ein mehrfach definierter Symbolfehler angezeigt.
quelle
Sie können eine statische Variable nicht deklarieren, ohne sie ebenfalls zu definieren (dies liegt daran, dass sich die statischen und externen Speicherklassenmodifikatoren gegenseitig ausschließen). Eine statische Variable kann in einer Header-Datei definiert werden. Dies würde jedoch dazu führen, dass jede Quelldatei, die die Header-Datei enthält, eine eigene private Kopie der Variablen hat, was wahrscheinlich nicht beabsichtigt ist.
quelle
const Variablen sind in C ++ standardmäßig statisch, aber extern C. Wenn Sie also C ++ verwenden, macht dies keinen Sinn, welche Konstruktion verwendet werden soll.
(7.11.6 C ++ 2003 und Apexndix C enthält Beispiele)
Beispiel für den Vergleich von Kompilierungs- / Linkquellen als C- und C ++ - Programm:
quelle
static
. Es signalisiert die Absicht / das Bewusstsein dessen, was der Programmierer tut, und behält die Parität mit anderen Arten von Deklarationen (und, fwiw, C) bei, denen das Implizite fehltstatic
. Es ist wie das Einbeziehenvirtual
und in letzter Zeitoverride
in Deklarationen übergeordneter Funktionen - nicht notwendig, aber viel selbstdokumentierender und im letzteren Fall der statischen Analyse förderlich.const
nur für eine Variable in einem Header mit verwendet wirdg++ (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2)
. Es ergaben sich ungefähr 150 mehrfach definierte Symbole (eines für jede Übersetzungseinheit, in der der Header enthalten war). Ich denke , wir müssen entwederstatic
,inline
oder ein anonymes / unbenannte Namespace die externe Bindung zu vermeiden.const int
innerhalb des Namespace-Bereichs und im globalen Namespace versucht . Und es kompilierte und folgt der Regel „Objekte const deklarierte und nicht explizit deklarierte extern haben interne Bindung.““.... Vielleicht in Projekt in irgendeinem Grunde diese Header in C kompilierte Quellen enthielten, in denen die Regeln ganz anders.Statisch verhindert, dass eine andere Kompilierungseinheit diese Variable auslagert, sodass der Compiler den Wert der Variablen, in dem sie verwendet wird, einfach "inline" und keinen Speicher für sie erstellen kann.
In Ihrem zweiten Beispiel kann der Compiler nicht davon ausgehen, dass eine andere Quelldatei sie nicht extern erstellt. Daher muss er diesen Wert tatsächlich irgendwo im Speicher speichern.
quelle
Statisch verhindert, dass der Compiler mehrere Instanzen hinzufügt. Dies wird beim # ifndef-Schutz weniger wichtig. Unter der Annahme, dass der Header in zwei separaten Bibliotheken enthalten ist und die Anwendung verknüpft ist, werden zwei Instanzen eingeschlossen.
quelle
static
"weniger wichtig" zu machen . und selbst mit beiden können Sie mehrere intern verknüpfte Definitionen erhalten, was wahrscheinlich nicht beabsichtigt ist.