Warum beziehen einige konstante Variablen zu einigen exportierten konstante Variablen erhalten den Wert 0?
-
06-09-2019 - |
Frage
Betrachten Sie die folgende. Ich habe zwei exportierte Konstanten wie folgt:
// somefile.h
extern const double cMyConstDouble;
extern const double cMyConstDouble2;
und
// somefile.cpp
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
Diese Konstanten werden jetzt irgendwo anders definieren zwei statische (lokal sichtbar) Konstanten verwiesen:
// someotherfile.cpp
#include "somefile.h"
static const double cAnotherDouble = 1.1*cMyConstDouble;
static const double cAnotherDouble2 = 1.1*cMyConstDouble2;
printf("cAnotherDouble = %g, cAnotherDouble2 = %g\n",
cAnotherDouble, cAnotherDouble2);
Welche liefert die folgende Ausgabe:
cAnotherDouble = 3.454, cAnotherDouble2 = 0
Warum ist das zweite Doppel 0? Ich verwende .NET 2003 C ++ Compiler (13.10.3077).
Lösung
Da cMyConstDouble als extern deklariert wird, Compiler ist nicht in der Lage seinen Wert zu übernehmen und erzeugt keine Kompilierung Initialisierung für cMyConstDouble2. Da die cMyConstDouble2 nicht Kompilierung initialisiert, dessen Reihenfolge der Initialisierung in Bezug auf cAnotherDouble2 zufällig ist (nicht definiert). Siehe statische Initialisierung Fiasko mehr Informationen.
Andere Tipps
Ich werde nicht auf meine Zehen in die Fragen der extern tauchen hier, aber warum legen Sie einfach nicht die consts in den entsprechenden Header-Dateien und vergessen Sie den „Export“, um sie mit extern? Dies ist, wie consts sollen in C ++ verwendet werden soll, und warum sie haben interne Bindung.
Mit anderen Worten:
// someheader.h
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
und # include, die Datei, wo immer sie gebraucht werden.
Das ist gefährlich, was als eine statische Variable in einer Quelldatei zu tun, hängt von der weiteren statischen Variablen in einer anderen CPP-Datei. Überprüfen Sie statische Initialisierung Fiasko für weitere Informationen.
Wenn Sie die Initialisierung von cMyConstDouble2
dazu ändern:
const double cMyConstDouble2 = 2.5*3.14;
Dann sollten Sie Ihr Programm korrekt verhalten. Der Grund dafür ist, dass Variablen, die
- Haben Sie POD Typ
- initialisiert mit konstanten Ausdrücken (1)
werden bei statischer Initialisierung initialisiert. Diese Initialisierungen umfassen
- Null Initialisierung von alle Objekte mit statischer Lagerdauer
- Initialisierungen von PODs initialisiert mit konstanten Ausdrücken
Ihre gezeigten Variablen, nur cMyConstDouble
erfüllt beiden Bedingungen bei statischer Initialisierung vollständig initialisiert werden. Allerdings ist cMyConstDouble2
nicht, da seine initializer nicht die Anforderungen eines konstanten Ausdrucks nicht erfüllt. Insbesondere weist es eine Variable, die nicht integralen Typen haben (hier hat es Gleitkommatyps). Allerdings Gleitkomma Literalen sind erlaubt in arithmetischen konstanten Ausdrücken. Deshalb 2.5*3.14
ein arithmetischer konstanter Ausdruck ist. Und aus diesem Grunde auf, dass die Initialisierung zu ändern erfordert es statisch initialisiert werden.
Was mit cMyConstDouble2
passieren wird, wenn Sie mit dem nicht konstanten Ausdruck bleiben? Die Antwort ist, Sie wissen es nicht. Der Standard ermöglicht es, dass variable statisch initialisiert werden, sich aber nicht so tun müssen. In Ihrem Fall wurde es dynamisch initialisiert - also seinen Wert nur nach statischer Initialisierung noch Null war. Um ein Gefühl dafür zu bekommen, wie komplizierte , das heißt, hier ist ein Beispiel:
inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
// may be statically initialized to 0.0 or
// dynamically initialized to 1.0
double d1 = fd(); // may be initialized statically to 1.0
Wenn die dynamische Initialisierung ändert sich nicht, andere statische Speichergröße (zufrieden in Ihre Code) und wenn die statische Initialisierung den gleichen Wert erzeugen würde, wie sie durch dynamische Initialisierung erzeugt werden, wenn alle Objekte nicht erforderlich statisch initialisiert werden würde dynamisch initialisiert werden (auch zufrieden in Ihre Code) - dann wird die Variable erlaubt statisch initialisiert werden. Diese beiden Bedingungen sind auch zufrieden in den obigen Code für beide Variablen d2
und d1
:
Analyse von d2
-
= d1
keine andere statische Speichervariable ändern - Wenn beide
d2
undd1
dynamisch initialisiert, dann würded2
0.0
initialisiert werden, dad2
vord1
definiert ist, und dynamische Initialisierung desd2
würde den Wert vond1
als der Zustand unmittelbar nach dem statischen Initialisierung greifen (wo nur Null Initialisierung vond1
statt).
Analyse von d1
-
= fd()
keine andere statische Speichervariable ändern - Wenn beide
d2
undd1
dynamisch initialisiert werden, dann wird initialisieren= fd()
d1
1.0
.
Also, der Compiler d1
statisch 1.0
initialisieren kann, weil beide Bedingungen für optionale statisch-Initialisierung erfüllt sind.
-
Wenn der Compiler
d1
undd2
dynamisch zu initialisieren entscheidet, dannd2
wird0.0
initialisiert , da sie den Wert derd1
greifen wird, wie es war kurz nach Null Initialisierung. -
Jedoch , wenn der Compiler
d1
statisch undd2
dynamisch zu initialisieren entscheidet, dannd2
wird initialisiert werden1.0
, da die dynamische Initialisierung desd2
den vollständig initialisiert Wert vond1
greifen, wie es unmittelbar nach statischer initializatio warn.
Ich bin mir nicht sicher, was der Wert von d2
ist, wenn d1
und d2
statisch initialisiert werden, though. Das heißt, ob d2
sollte die 0.0
oder die 1.0
packen, da es keine Reihenfolge für die statische Initialisierung definiert ist.
(1) Konstante Ausdrücke umfassen arithmetische Konstante Ausdrücke auch (nicht nur integrale Konstante Ausdrücke), wenn man bedenkt, Initialisierungsreihenfolge von Objekten mit statischer Speicherdauer.