2009-05-28 9 views
2

Betrachten Sie Folgendes. Ich habe zwei exportierte Konstanten wie folgt:Warum erhalten einige const-Variablen, die auf einige exportierte const-Variablen verweisen, den Wert 0?

// 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 verwiesen, um zwei statische (lokal sichtbar) Konstanten:

// 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); 

, die Ausbeuten die folgende Ausgabe:

cAnotherDouble = 3.454, cAnotherDouble2 = 0 

Warum ist die zweite Doppel 0? Ich benutze .NET 2003 C++ Compiler (13.10.3077).

Antwort

8

Da cMyConstDouble als extern deklariert ist, kann der Compiler seinen Wert nicht annehmen und generiert keine Initialisierungszeit für die Kompilierung von cMyConstDouble2. Da cMyConstDouble2 nicht initialisiert ist, ist die Reihenfolge der Initialisierung relativ zu cAnotherDouble2 zufällig (undefiniert). Weitere Informationen finden Sie unter static initialization fiasco.

+0

@Suma: Wenn das 'cMyConstDouble2' nicht konstant gefaltet ist, weil' cMyConstDouble' 'extern' ist, sollte das nicht auch bei' cAnotherDouble' passieren? Das hängt auch von 'cMyConstDouble' oder? Wie kommt es ist Wert richtig gedruckt als 3.454 – legends2k

+0

Reihenfolge der Initialisierung über Module ist undefiniert. In einem Fall war es schon gemacht, in der zweiten nicht. – Suma

9

Ich werde meinen Zeh nicht in die Probleme von extern eintauchen, aber warum platzierst du die Würmer einfach nicht in die entsprechenden Header-Dateien und vergisst, sie mit extern zu "exportieren"? Dies ist, wie in C++ COST verwendet werden soll, und warum sie interne Verknüpfungen haben.

Mit anderen Worten:

// someheader.h 
const double cMyConstDouble = 3.14; 
const double cMyConstDouble2 = 2.5*cMyConstDouble; 

und # include der Datei, wo immer sie gebraucht werden.

+0

Also * du * bist * dann deinen Zeh eintauchen? :-) +1 sowieso. – paxdiablo

+0

Nicht wirklich - meine Lösung verwendet nicht extern. –

+1

Eigentlich gibt es einen Grund, warum. Wir sind von deinem Weg hierher gegangen, weil sie enorme Verbindungszeiten verursacht haben. – ralphtheninja

3

Dies ist gefährlich, da Ihre eine statische Variable in einer Quelldatei von der anderen statischen Variable in einer anderen cpp-Datei abhängt. Überprüfen Sie static initialization fiasco für weitere Informationen.

+0

Es ist im Allgemeinen gefährlich, aber dies gilt nicht, wenn die Kompilierzeitinitialisierung durch Konstanten stattfindet. Meine Antwort zeigt auf die Tatsache, dass, während der Code wie Kompilierzeit Initialisierung aussehen kann, in der Tat ist es nicht wegen extern. – Suma

2

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

  • Have POD Typ
  • mit konstanten Ausdrücken initialisiert (1)

bei statischer Initialisierung initialisiert werden. Diese Initialisierungen umfassen

  • Null Initialisierung von alle Objekte statischen Lagerdauer
  • Initialisierungen von PODs initialisiert mit konstanten Ausdrücken

Ihrer gezeigten Variablen mit nur cMyConstDouble erfüllt beide Bedingungen werden vollständig initialisiert zur statischen Initialisierungszeit. cMyConstDouble2 tut dies jedoch nicht, da sein Initialisierer die Anforderungen eines konstanten Ausdrucks nicht erfüllt.Insbesondere enthält es eine Variable, die keinen Integraltyp hat (hier hat sie Gleitkommatyp). Fließkomma Literalesind zulässig in arithmetischen Konstantenausdrücken. Deshalb ist 2.5*3.14 ein arithmetischer Konstantenausdruck. Aus diesem Grund muss der Initialisierer geändert werden, damit er statisch initialisiert wird.


Was mit cMyConstDouble2 passieren wird, wenn Sie mit dem nicht konstanten Ausdruck bleiben? Die Antwort ist, du weißt es nicht. Der Standard ermöglicht, dass diese Variable statisch initialisiert wird, erfordert dies jedoch nicht. In Ihrem Fall wurde es dynamisch initialisiert - somit war sein Wert gleich nach der statischen Initialisierungszeit immer noch Null. Um ein Gefühl dafür, wie komplizierten zu erhalten, die, 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 (in zufrieden Ihren Code) und wenn die statischen Initialisierung würde den gleichen Wert erzeugen, der bei dynamischer Initialisierung erzeugt würde, wenn alle Objekte, die nicht statisch initialisiert werden müssen, dynamisch initialisiert werden (auch erfüllt in Ihr Code) - dann darf die Variable 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 zu 0.0 initialisiert werden, weil d2 vor d1 definiert ist, und dynamische Initialisierung von d2 wäre gr. ab dem Wert d1 ab dem Zustand unmittelbar nach der statischen Initialisierung (wo nur Null Initialisierung von d1 stattfand).

Analyse von d1

  • = fd() keine andere statische Speicher
  • Variable ändern Wenn beide d2 und d1 dynamisch initialisiert werden, dann wird = fd()d1-1.0 initialisieren.

So kann der Compiler d1 statisch 1.0, initialisiert werden, da beide Bedingungen für optionale statisch-Initialisierung erfüllt sind.

  • Wenn der Compiler entscheidet d1 und d2 dynamisch zu initialisieren, dann d2 wird 0.0 initialisiert werden, da sie den Wert von d1 greifen, wie es kurz nach Null Initialisierung war.

  • jedoch, wenn entscheidet der Compiler d1 statisch und d2 dynamisch zu initialisieren, dann d2 wird 1.0, initialisiert werden, da die dynamische Initialisierung der d2 den vollständig initialisierte Wert von d1 greifen, wie es war kurz nach der statischen Initialisierung.

Ich bin mir nicht sicher, was der Wert von d2 ist, wenn d1undd2 statisch initialisiert werden, though. Das heißt, ob d2 die 0.0 oder 1.0 greifen soll, da keine Reihenfolge für die statische Initialisierung definiert ist.


(1) Konstante Ausdrücke umfassen arithmetischen konstanten Ausdrücke auch (nicht nur ganzzahlige konstante Ausdrücke), wenn die Initialisierung Reihenfolge von Objekten mit statischer Speicherdauer berücksichtigen.

Verwandte Themen