Pourquoi certaines variables const se référant à certaines variables const exportées obtenir la valeur 0?
-
06-09-2019 - |
Question
Considérez ce qui suit. J'ai deux constantes exportées comme suit:
// somefile.h
extern const double cMyConstDouble;
extern const double cMyConstDouble2;
et
// somefile.cpp
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
Ces constantes sont maintenant référencées un autre endroit pour définir deux constantes statiques (localement visibles):
// 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);
Ce qui donne le résultat suivant:
cAnotherDouble = 3.454, cAnotherDouble2 = 0
Pourquoi le deuxième double 0? J'utilise .NET 2003 compilateur C (13.10.3077).
La solution
Parce que cMyConstDouble est déclarée comme extern, le compilateur n'est pas en mesure d'assumer sa valeur et ne génère pas d'initialisation de compilation pour cMyConstDouble2. Comme le cMyConstDouble2 est compile pas le temps initialisé, l'ordre d'initialisation par rapport à cAnotherDouble2 est aléatoire (non défini). Voir initialisation statique fiasco pour plus informations.
Autres conseils
Je ne vais pas plonger mon orteil dans les questions de extern ici, mais pourquoi ne vous placez pas tout simplement les consts dans les fichiers d'en-tête appropriés et oublier « exporter » les utiliser extern? Voici comment consts sont censés être utilisés en C ++, et pourquoi ils ont une liaison interne.
En d'autres termes:
// someheader.h
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
et #include ce fichier chaque fois que vous en avez besoin.
Ceci est dangereux de faire comme une variable statique dans un fichier source dépend de la variable statique autre dans un autre fichier cpp. Consultez d'initialisation statique fiasco pour plus d'informations.
Si vous modifiez l'initialisation de cMyConstDouble2
à ce ici:
const double cMyConstDouble2 = 2.5*3.14;
Ensuite, votre programme doit se comporter correctement. La raison est que les variables
- ont le même type POD
- sont initialisés avec des expressions constantes (1)
sont initialisées au moment de l'initialisation statique. Ces initialisations comprennent
- zéro initialisation de tous objets ayant une durée de stockage statique
- initialisations de PODs initialisées avec des expressions constantes
vos variables présentées, seulement cMyConstDouble
satisfait les deux conditions d'être complètement initialisé au moment de l'initialisation statique. Cependant, cMyConstDouble2
n'a pas, depuis sa initialiseur ne satisfait pas aux exigences d'une expression constante. Il comprend notamment, une variable qui ne dispose pas de type intégral (ici, il est de type à virgule flottante). Cependant, virgule flottante littéraux sont autorisés dans les expressions arithmétiques constantes. Voilà pourquoi 2.5*3.14
est une expression constante arithmétique. Et c'est pourquoi changer le initialiseur à qui nécessitera d'être initialisé statiquement.
Qu'est-ce qui va se passer avec cMyConstDouble2
si vous restez avec l'expression non-constante? La réponse est, vous ne savez pas. La norme permet cette variable à statiquement initialisé, mais ne nécessite pas de le faire. Dans votre cas, il a été initialisé dynamiquement - donc sa juste valeur après le temps d'initialisation statique était encore nul. Pour avoir une idée de la façon dont compliqué qui est, voici un exemple:
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
Si l'initialisation dynamique ne change pas une autre variable de stockage statique (satisfait dans votre code) et lorsque l'initialisation statique produirait la même valeur que serait produite par l'initialisation dynamique lorsque tous les objets non qui doit être initialisé statiquement serait initialisé dynamiquement (également satisfaite dans votre code) - la variable est autorisée à initialiser statiquement. Ces deux conditions sont également satisfaites dans le code ci-dessus pour les deux variables d2
et d1
:
Analyse des d2
-
= d1
ne change pas toute autre variable de stockage statique - Lorsque sont initialisés à la fois
d2
etd1
dynamiquement,d2
serait alors initialisées à0.0
, card2
est défini avantd1
et l'initialisation dynamique ded2
saisirait la valeur ded1
comme de l'état juste après l'initialisation statique (où seul zéro initialisation ded1
a eu lieu).
Analyse des d1
-
= fd()
ne change pas toute autre variable de stockage statique - Lorsque sont initialisés à la fois
d2
etd1
dynamiquement, puis= fd()
REINITIALISERAd1
à1.0
.
Ainsi, le compilateur peut initialiser d1
statiquement à 1.0
, parce que les deux conditions pour l'initialisation-option-statique sont remplies.
-
Si, car il saisira la valeur de
d1
comme il était le compilateur décide d'initialiser dynamiquementd2
etd2
, puis0.0
seront réinitialisés àd1
juste après l'initialisation de zéro. -
Cependant , si le compilateur décide d'initialiser
d1
statiquement etd2
dynamiquement, puisd2
sera initialisé à1.0
, depuis l'initialisation dynamique ded2
va saisir la valeur pleinement initialisées ded1
comme il était juste après initializatio statiquen.
Je ne suis pas sûr de ce que la valeur de d2
est quand d1
et d2
est initialisés statiquement, cependant. Autrement dit, si d2
est censé saisir le 0.0
ou 1.0
, car il n'y a pas d'ordre défini pour l'initialisation statique.
(1) Les expressions constantes comprennent aussi des expressions arithmétiques constantes (non seulement des expressions constantes intégrales), en considérant l'ordre d'initialisation d'objets avec une durée de stockage statique.