Por que algumas variáveis ??const referentes a algumas variáveis ??const exportados obter o valor 0?

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

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

Foi útil?

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 e d1 são inicializados de forma dinâmica, então d2 iria ser inicializado para 0.0, porque d2 é definida antes d1, e inicialização dinâmica de d2 iria pegar o valor de d1 como do estado logo após inicialização estática (onde apenas de zero inicialização de d1 ocorreu).

Análise de d1

  • = fd() não muda qualquer variável outra armazenamento estático
  • Quando ambos d2 e d1 são inicializados de forma dinâmica, então = fd() irá inicializar d1 para 1.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 e d2 dinamicamente, então d2 será inicializado para 0.0 , uma vez que vai agarrar o valor de d1 como era logo após a inicialização do zero.

  • No entanto , se o compilador decide inicializar d1 estaticamente e d2 dinamicamente, então d2 será inicializado para 1.0 , uma vez que a inicialização dinâmica de d2 vai agarrar o valor totalmente inicializados de d1 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top