Warum beziehen einige konstante Variablen zu einigen exportierten konstante Variablen erhalten den Wert 0?

StackOverflow https://stackoverflow.com/questions/920615

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).

War es hilfreich?

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 und d1 dynamisch initialisiert, dann würde d2 0.0 initialisiert werden, da d2 vor d1 definiert ist, und dynamische Initialisierung des d2 würde den Wert von d1 als der Zustand unmittelbar nach dem statischen Initialisierung greifen (wo nur Null Initialisierung von d1 statt).

Analyse von d1

  • = fd() keine andere statische Speichervariable ändern
  • Wenn beide d2 und d1 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 und d2 dynamisch zu initialisieren entscheidet, dann d2 wird 0.0 initialisiert , da sie den Wert der d1 greifen wird, wie es war kurz nach Null Initialisierung.

  • Jedoch , wenn der Compiler d1 statisch und d2 dynamisch zu initialisieren entscheidet, dann d2 wird initialisiert werden 1.0 , da die dynamische Initialisierung des d2 den vollständig initialisiert Wert von d1 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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top