2

次のことを考慮してください。次のように2つのエクスポートされた定数があります。

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

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

これらの定数は、2つの静的(ローカルに表示される)定数を定義するために別の場所で参照されるようになりました。

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

これにより、次の出力が得られます。

cAnotherDouble = 3.454, cAnotherDouble2 = 0

2番目のdoubleが0であるのはなぜですか?.NET 2003 C ++コンパイラ(13.10.3077)を使用しています。

4

4 に答える 4

9

ここではexternの問題に足を踏み入れるつもりはありませんが、constsを適切なヘッダーファイルに配置せず、externを使用してそれらを「エクスポート」することを忘れないのはなぜですか。これが、C ++でconstsが使用されることになっている方法であり、内部リンクがある理由です。

言い換えると:

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

必要な場所にそのファイルを#includeします。

于 2009-05-28T12:42:05.570 に答える
8

cMyConstDoubleはexternとして宣言されているため、コンパイラはその値を想定できず、cMyConstDouble2のコンパイル時の初期化を生成しません。cMyConstDouble2はコンパイル時に初期化されないため、cAnotherDouble2に対する初期化の順序はランダムです(未定義)。詳細については、静的初期化の大失敗を参照してください。

于 2009-05-28T12:42:51.730 に答える
3

1つのソースファイル内の1つの静的変数が、別のcppファイル内の別の静的変数に依存しているため、これを行うのは危険です。詳細については、静的初期化の大失敗を確認してください。

于 2009-05-28T12:44:08.950 に答える
2

ここでの初期化cMyConstDouble2をこれに変更すると:

const double cMyConstDouble2 = 2.5*3.14;

その後、プログラムは正しく動作するはずです。その理由は、

  • PODタイプあり
  • 定数式で初期化されている(1)

静的初期化時に初期化されます。これらの初期化には、

  • 静的ストレージ期間を持つすべてのオブジェクトのゼロ初期化
  • 定数式で初期化された POD の初期化

表示された変数のうち、cMyConstDouble静的初期化時に完全に初期化されるという両方の条件のみを満たします。ただし、cMyConstDouble2その初期化子が定数式の要件を満たさないため、そうではありません。特に、整数型を持たない変数 (ここでは浮動小数点型) が含まれます。ただし、算術定数式では浮動小数点リテラル を使用できます。2.5*3.14これが算術定数式である理由です。そのため、イニシャライザをそのように変更するには、静的に初期化する必要があります。


cMyConstDouble2非定数式のままだとどうなりますか? 答えは、わかりません。標準では、その変数を静的に初期化することを許可していますが、そうする必要はありません。あなたの場合、それは動的に初期化されました-したがって、静的初期化時間の直後の値はまだゼロでした。それがいかに複雑かを理解するために、以下に例を示します。

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

動的初期化が他の静的ストレージ変数を変更しない場合 (コードで満たされいる場合)、および静的初期化が、静的に初期化する必要のないすべてのオブジェクトが動的に初期化されるときに動的初期化によって生成される値と同じ値を生成する場合 (コードでも満足されます) - 変数を静的に初期化することが許可されます。d2これらの 2 つの条件は、変数との両方について、上記のコードでも満たされていますd1

の分析d2

  • = d1他の静的ストレージ変数は変更しません
  • d2との両方d1が動的に初期化される場合、d2は に初期化されます。これは、 が の前に定義され0.0ているためです。また、 の動的初期化は、静的初期化の直後の状態での値を取得します (ゼロ初期化のみが行われた場所)。d2d1d2d1d1

の分析d1

  • = fd()他の静的ストレージ変数は変更しません
  • d2との両方d1が動的に初期化されると、= fd()は に初期化d1され1.0ます。

したがって、optional-static-initialization の両方の条件が満たされるため、コンパイラはd1に静的に初期化できます。1.0

  • コンパイラが動的に初期d1化することを決定した場合、ゼロ初期化直後のように の値を取得するため、に初期化されます。d2d20.0d1

  • ただし、コンパイラが静的および動的に初期化することを決定した場合、 は に初期化されます。これは、 の動的初期化が、静的初期化直後のように の完全に初期化された値を取得するためです。d1d2d21.0d2d1

ただし、の値d2がいつd1 で、 d2静的に初期化されるかはわかりません。つまり、静的初期化の順序が定義されていないため、 がまたはd2を取得する必要があるかどうかです。0.01.0


(1)静的記憶域期間を持つオブジェクトの初期化順序を考慮する場合、定数式には (整数定数式だけでなく) 算術定数式も含まれます。

于 2009-05-28T16:00:20.037 に答える