web-dev-qa-db-ja.com

静的変数とグローバル変数はいつ初期化されますか?

C++では、staticおよびglobalオブジェクトがmain関数の前に構築されることを知っています。しかし、ご存知のように、Cでは、mainの前にそのような種類initialization procedureはありません。

たとえば、私のコードでは:

int global_int1 = 5;
int global_int2;
static int static_int1 = 4;
static int static_int2;
  • これらの4つの変数はいつ初期化されますか
  • 54などの初期化の値は、コンパイル中にどこに保存されますか?初期化時にそれらを管理する方法は?

編集:
2番目の質問の明確化。

  • 私のコードでは、5initializeglobal_int1に使用しているので、コンパイラはassign5からglobal_intに?たとえば、コンパイラは最初に5値をどこか(テーブルなど)に保存し、初期化の開始時にこの値を取得します。
  • 「初期化時にそれらを管理する方法」については、それは本当にあいまいであり、私自身はまだ解釈する方法はありません。時々、質問を説明するのは簡単ではありません。私はまだ完全に質問をマスターしていないので、それを見落としてください。
35
Zachary

静的およびグローバルオブジェクトとは、名前空間で定義された静的な有効期間を持つオブジェクトを意味すると思います。そのようなオブジェクトがローカルスコープで定義されている場合、ルールはわずかに異なります。

正式には、C++はこのような変数を3段階で初期化します。1.ゼロ初期化2.静的初期化3.動的初期化この言語は、動的初期化が必要な変数と静的初期化が必要な変数も区別します。最初にゼロが初期化され、次に静的初期化を持つオブジェクトが初期化されてから、動的初期化が発生します。

単純な最初の近似として、動的初期化は、いくつかのコードを実行する必要があることを意味します。通常、静的初期化はしません。したがって:

extern int f();

int g1 = 42;    //  static initialization
int g2 = f();   //  dynamic initialization

別の近似は、静的初期化がCがサポートするもの(静的寿命を持つ変数の場合)であり、その他はすべて動的であることです。

コンパイラがこれを行う方法は、もちろん初期化に依存しますが、実行可能ファイルがディスクからメモリにロードされるディスクベースのシステムでは、静的初期化の値はディスク上のイメージの一部であり、システムによって直接ロードされますディスク。古典的なUnixシステムでは、グローバル変数は3つの「セグメント」に分割されます。

テキスト:
書き込み保護された領域にロードされるコード。 `const`型の静的変数もここに配置されます。
データ:
静的初期化子を持つ静的変数。
bss:
初期化なしの静的変数(CおよびC++)または動的初期化(C++)。実行可能ファイルにはこのセグメントのイメージが含まれておらず、システムはコードを開始する前に単にすべてを「0」に設定します。

現代のシステムの多くは、まだ似たようなものを使用していると思います。

編集:

補足説明:上記はC++ 03を指します。既存のプログラムの場合、C++ 11はおそらく何も変更しませんが、constexpr(一部のユーザー定義関数はまだ静的初期化できることを意味します)とスレッドローカル変数を追加します。ワームの缶。

23
James Kanze

序文:「静的」という言葉には、C++でさまざまな意味があります。混乱しないでください。

すべてのオブジェクトには静的な保存期間があります。それは、自動でも動的でもないためです。 (スレッドローカルではありませんが、スレッドローカルは静的に少し似ています。)

C++では、静的オブジェクトは、静的初期化と動的初期化の2つのフェーズで初期化されます。

  • 動的な初期化を実行するには実際のコードが必要であるため、これはコンストラクター呼び出しで始まるオブジェクト、または初期化子が実行時にのみ評価できる式である場合に発生します。

  • 静的初期化は、初期化子が静的に認識され、コンストラクターを実行する必要がない場合です。 (静的初期化はzero-initializationまたはconstant-initializationのいずれかです。)これは、定数イニシャライザーを使用したint変数の場合であり、これらは実際に静的フェーズで初期化されます。

  • (動的初期化を使用する静的ストレージ変数は、alsoゼロで初期化され、他に何かが起こる前に。)

重要な点は、静的初期化フェーズがまったく「実行」されないことです。データは最初からそこにあります。これは、静的な初期化に関係する「順序付け」などの動的プロパティがないことを意味します。必要に応じて、初期値はプログラムバイナリにハードコーディングされます。

15
Kerrek SB

これらの4つの変数はいつ初期化されますか?

あなたが言うように、これはプログラムの起動前、つまりmainが始まる前に起こります。 Cはそれをさらに指定しません。 C++では、これらは、より複雑なコンストラクターまたは初期化子を持つオブジェクトの前の静的初期化フェーズの間に発生します。

コンパイル中に5や4などの初期化の値が保存される場所は?

通常、非ゼロ値はプログラムファイルのデータセグメントに格納され、ゼロ値は変数に十分なメモリを予約するbssセグメントに格納されます。プログラムが起動すると、データセグメントがメモリにロードされ、bssセグメントがゼロに設定されます。 (もちろん、言語標準ではこれが指定されていないため、コンパイラはmainを実行する前に各変数を初期化するコードを生成するなど、他のことを行うことができます)。

5
Mike Seymour

標準からの言い換え:

動的ストレージ期間がなく、スレッドローカルストレージ期間がなく、ローカルではなく、静的ストレージ期間があるすべての変数。言い換えると、すべてのグローバルには静的な保存期間があります。

動的な初期化を伴う静的オブジェクトは、必ずしもmain関数の最初のステートメントの前に作成されるとは限りません。これらのオブジェクトがmainの最初のステートメントの前に作成されるか、または初期化される静的変数と同じ変換単位で定義された関数または変数の最初の使用の前に作成されるかについて定義された実装です。

したがって、コードでは、global_int1とstatic_int1は静的に初期化されるため、mainの最初のステートメントの前に確実に初期化されます。ただし、global_int2とstatic_int2は動的に初期化されるため、これらの初期化は上記のルールに従って定義された実装です。

2番目の点については、あなたが何を言っているのか理解できません。明確にできますか?

2
scl