¿Por qué algunas variables const referencia a algunas variables const exportados obtener el valor 0?

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

Pregunta

Tenga en cuenta lo siguiente. Tengo dos constantes exportados como sigue:

// somefile.h
extern const double cMyConstDouble;
extern const double cMyConstDouble2;

y

// somefile.cpp
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;

Estas constantes se ahora referencia a algún otro lugar para definir dos constantes estáticas (localmente visible):

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

que produce el siguiente resultado:

cAnotherDouble = 3.454, cAnotherDouble2 = 0

¿Por qué es el segundo doble 0? Estoy usando .NET 2003 compilador de C ++ (13.10.3077).

¿Fue útil?

Solución

Debido cMyConstDouble se declara como extern, compilador no es capaz de asumir su valor y no genera una inicialización de tiempo de compilación para cMyConstDouble2. Como no es tiempo de compilación inicializa el cMyConstDouble2, su orden de inicialización en relación con cAnotherDouble2 es aleatorio (indefinido). Ver inicialización estática fiasco para más información.

Otros consejos

No voy a mojar mi dedo del pie en los temas de extern aquí, pero ¿por qué simplemente no colocar los consts en los archivos de cabecera apropiados y olvidarse de "exportar" usando extern? Así es como se supone consts para ser utilizado en C ++, y por qué tienen vinculación interna.

En otras palabras:

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

y #include ese archivo donde los necesite.

Esto es algo peligroso como su una variable estática en un archivo de origen depende de la otra variable estática en otro archivo CPP. Compruebe estática inicialización fiasco para más información.

Si cambia la inicialización de cMyConstDouble2 a esta aquí:

const double cMyConstDouble2 = 2.5*3.14;

A continuación, el programa debe comportarse correcta. La razón de esto es que las variables que

  • tipo tienen POD
  • se inicializan con expresiones constantes (1)

se inicializan en tiempo de inicialización estática. Estos inicializaciones incluyen

  • Cero inicialización de todos objetos que tienen una duración de almacenamiento estático
  • Inicializaciones de vainas inicializados con expresiones constantes

De las variables que se muestran, sólo satisface cMyConstDouble ambas condiciones de ser totalmente inicializado en tiempo de inicialización estática. Sin embargo, cMyConstDouble2 no es así, ya que su inicializador no satisface los requisitos de una expresión constante. En particular, se incluye una variable que no tiene tipo integral (en este caso, se ha tipos de puntos flotantes). Sin embargo, en coma flotante literales son permitidos en las expresiones aritméticas constantes. Por eso 2.5*3.14 es una expresión constante aritmética. Y es por eso cambiar el inicializador para que lo requerirá para inicializar estáticamente.


¿Qué pasará con cMyConstDouble2 si se queda con la expresión no constante? La respuesta es, no se sabe. La Norma permite que la variable que se inicializa de forma estática, pero no requiere que lo haga. En su caso, se inicializa de forma dinámica - por lo tanto su valor justo después de tiempo de inicialización estática estaba siendo cero. Para hacerse una idea de cómo complicado , es decir, aquí es un ejemplo:

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 la inicialización dinámica no cambia ninguna otra variable de almacenamiento estático (satisfechos en su Código) y cuando la inicialización estática produciría el mismo valor que sería producida por la inicialización dinámico cuando no todos los objetos requerido para ser inicializado de forma estática se inicializa de forma dinámica (también satisfechos en su código) - entonces se permite la variable que ser inicializado de forma estática. Estas dos condiciones son también satisfechos en el código anterior para ambas variables d2 y d1:

Análisis de d2

  • = d1 no cambia cualquier otra variable de almacenamiento estático
  • Cuando tanto d2 y d1 se inicializan dinámicamente, a continuación, d2 sería inicializa a 0.0, porque d2 se define antes d1, y la inicialización dinámica de d2 habría agarrar el valor de d1 como del estado justo después de la inicialización estática (donde sólo cero inicialización de d1 tuvo lugar).

Análisis de d1

  • = fd() no cambia cualquier otra variable de almacenamiento estático
  • Cuando tanto d2 y d1 se inicializan dinámicamente, a continuación, = fd() inicializará d1 a 1.0.

Por lo tanto, el compilador puede inicializar d1 estáticamente a 1.0, porque se cumplen ambas condiciones para opcional-estático-inicialización.

  • el compilador decide inicializar d1 y d2 dinámicamente, a continuación, d2 se inicializará a 0.0 , ya que va a captar el valor de d1 como lo fue justo después de la inicialización de cero.

  • No obstante , si el compilador decide inicializar d1 estática y d2 dinámicamente, a continuación, se iniciará d2 a 1.0 , ya la inicialización dinámica de d2 se agarra el valor inicializado completamente de d1 ya que fue justo después de initializatio estáticanorte.

No estoy seguro de lo que es el valor de d2 cuando d1 y d2 se inicializa de forma estática, sin embargo. Es decir, si se supone que d2 agarrar el 0.0 o la 1.0, ya que no hay un orden definido para la inicialización estática.


(1) Las expresiones constantes incluyen expresiones constantes aritméticas también (no sólo expresiones constantes integrales), al considerar orden de inicialización de objetos con una duración de almacenamiento estático.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top