Por que algumas variáveis ??const referentes a algumas variáveis ??const exportados obter o valor 0?
-
06-09-2019 - |
Pergunta
Considere o seguinte. Eu tenho duas constantes exportados da seguinte forma:
// somefile.h
extern const double cMyConstDouble;
extern const double cMyConstDouble2;
e
// somefile.cpp
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
Estas constantes são agora referenciados em algum outro lugar para definir dois estático (localmente visível) constantes:
// 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 produz o seguinte resultado:
cAnotherDouble = 3.454, cAnotherDouble2 = 0
Por que é a segunda dupla 0? Estou usando .NET compilador 2003, C ++ (13.10.3077).
Solução
Porque cMyConstDouble é declarado como externo, compilador não é capaz de assumir o seu valor e não gera uma inicialização tempo de compilação para cMyConstDouble2. Como o cMyConstDouble2 não é tempo de compilação inicializado, a sua ordem de inicialização em relação ao cAnotherDouble2 é aleatório (indefinido). Consulte estática inicialização fiasco para obter mais informações.
Outras dicas
Eu não vou mergulhar meu dedo do pé para as questões de extern aqui, mas por que você simplesmente não colocar os consts nos arquivos de cabeçalho apropriadas e esquecer "exportar"-los usando extern? Isto é como consts é suposto ser usado em C ++, e por que eles têm ligação interna.
Em outras palavras:
// someheader.h
const double cMyConstDouble = 3.14;
const double cMyConstDouble2 = 2.5*cMyConstDouble;
e #include esse arquivo sempre que você precisar deles.
Esta é coisa perigosa para fazer como sua variável estático em um arquivo de origem depende da variável outra estática em outro arquivo cpp. Verifique estática inicialização fiasco para obter mais informações.
Se você alterar a inicialização do cMyConstDouble2
a esta aqui:
const double cMyConstDouble2 = 2.5*3.14;
Em seguida, o programa deve se comportar correta. A razão para isso é que as variáveis ??que
- tipo têm POD
- são inicializados com expressões constantes (1)
são inicializados em tempo de inicialização estática. Essas inicializações incluem
- Zero inicialização do todas objetos com duração de armazenagem estática
- Initializations de vagens inicializados com expressões constantes
De suas variáveis ??apresentadas, apenas satisfaz ambas as condições de ser totalmente inicializado em tempo de inicialização estática cMyConstDouble
. No entanto, cMyConstDouble2
não faz, desde a sua initializer não satisfaz as exigências de uma expressão constante. Em particular, ele inclui uma variável que não tem tipo integral (aqui, tem flutuante tipo de ponto). No entanto, em ponto flutuante literais são permitido em expressões constantes aritméticas. É por isso que 2.5*3.14
é uma expressão constante aritmética. E é por isso mudando o inicializador de que vai exigir que ele seja estaticamente inicializado.
O que vai acontecer com cMyConstDouble2
se você ficar com a expressão não constante? A resposta é, você não sabe. O padrão permite que variável a ser estaticamente inicializado, mas não exige que ela faça isso. No seu caso, ele foi inicializado dinamicamente - assim o seu valor apenas após o tempo de inicialização estática ainda de zero era. Para se ter uma idéia de como complicado que é, aqui está um exemplo:
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
Se a inicialização dinâmica não muda qualquer outra variável estática de armazenagem (satisfeita em o código) e quando a inicialização estática produziria o mesmo valor que seria produzido pela inicialização dinâmica quando nem tudo objetos necessário para ser estaticamente inicializado iria ser inicializado de forma dinâmica (também satisfeito em o código) - então a variável é permitido ser inicializado estaticamente. Estas duas condições também estão satisfeitos no código acima para ambas as variáveis ??d2
e d1
:
Análise de d2
-
= d1
não muda qualquer variável outra armazenamento estático - Quando ambos
d2
ed1
são inicializados de forma dinâmica, entãod2
iria ser inicializado para0.0
, porqued2
é definida antesd1
, e inicialização dinâmica ded2
iria pegar o valor ded1
como do estado logo após inicialização estática (onde apenas de zero inicialização ded1
ocorreu).
Análise de d1
-
= fd()
não muda qualquer variável outra armazenamento estático - Quando ambos
d2
ed1
são inicializados de forma dinâmica, então= fd()
irá inicializard1
para1.0
.
Assim, o compilador pode inicializar d1
estaticamente para 1.0
, porque sejam respeitadas as condições para opcional-static-inicialização.
-
Se o compilador decide inicializar
d1
ed2
dinamicamente, entãod2
será inicializado para0.0
, uma vez que vai agarrar o valor ded1
como era logo após a inicialização do zero. -
No entanto , se o compilador decide inicializar
d1
estaticamente ed2
dinamicamente, entãod2
será inicializado para1.0
, uma vez que a inicialização dinâmica ded2
vai agarrar o valor totalmente inicializados ded1
como era apenas após initializatio estátican.
Eu não tenho certeza do que o valor de d2
é quando d1
e d2
é inicializado estaticamente, no entanto. Isto é, se d2
é suposto para pegar o 0.0
ou o 1.0
, já que não há ordem definida para inicialização estática.
(1) Expressões constantes incluem expressões constantes aritméticas também (não só expressões constantes integrais), quando se considera a ordem de inicialização de objetos com duração de armazenagem estática.