質問

SIOF について本で読んでいたのですが、次のような例がありました。

//file1.cpp
extern int y;
int x=y+1;

//file2.cpp
extern int x;
int y=x+1;  

さて、私の質問は次のとおりです。
上記のコードでは、次のようなことが起こりますか?

  1. file1.cpp のコンパイル中、コンパイラーは y をそのままにし、ストレージを割り当てません。
  2. コンパイラは x にストレージを割り当てますが、初期化はしません。
  3. file2.cpp のコンパイル中、コンパイラは x をそのまま残します。つまり、それにストレージを割り当てません。
  4. コンパイラは y にストレージを割り当てますが、初期化はしません。
  5. file1.o と file2.o をリンクするときに、file2.o を最初に初期化するので、次のようになります。
    xの初期値は0になるのでしょうか?それとも初期化されないのでしょうか?
役に立ちましたか?

解決

初期化手順は、C++ 標準の 3.6.2「非ローカル オブジェクトの初期化」に記載されています。

ステップ1: x そして y 他の初期化が行われる前に、ゼロで初期化されます。

ステップ2: x または y 動的に初期化されますが、標準では指定されていません。その変数は値を取得します 1 他の変数はゼロで初期化されるためです。

ステップ 3:もう一方の変数は動的に初期化され、値が取得されます。 2.

他のヒント

SIOF はほとんどがランタイム アーティファクトであり、コンパイラとリンカーはそれとはあまり関係がありません。atexit() 関数について考えてみましょう。この関数は、プログラム終了時に呼び出される関数を登録します。多くの CRT 実装にはプログラムの初期化に同様の機能があり、それを atinit() と呼びます。

これらのグローバル変数を初期化するにはコードを実行する必要がありますが、値はコンパイラによって決定できません。したがって、コンパイラは式を実行して値を割り当てるマシンコードのスニペットを生成します。これらのスニペットは、main() を実行する前に実行する必要があります。

そこで atinit() が登場します。一般的な CRT 実装は、atinit 関数ポインターのリストをたどって、初期化スニペットを順番に実行します。問題は、関数が atinit() リストに登録される順序です。atexit() には明確に定義された LIFO 順序があり、コードが atexit() を呼び出す順序によって暗黙的に決定されますが、atinit 関数の場合はそうではありません。言語仕様では順序は必要ありません。コード内で順序を指定することはできません。SIOF はその結果です。

考えられる実装の 1 つは、コンパイラーが別のセクションで関数ポインターを発行することです。リンカはそれらをマージし、atinit リストを生成します。コンパイラがこれを行う場合、初期化順序はオブジェクト ファイルをリンクする順序によって決まります。マップ ファイルを見てください。コンパイラがこれを行う場合は atinit セクションが表示されるはずです。atinit という名前にはなりませんが、「init」を含む何らかの名前になる可能性があります。main() を呼び出す CRT ソース コードを見てみると、同様に洞察が得られるはずです。

全体のポイント(と、それは「大失敗」と呼ばれる理由)それはは、このような場合に何が起こるかどんな確信のと言うことは不可能だということです。基本的に、あなたが不可能な何かを求めている(二つの変数はそれぞれ、一方が他方より大きいこと)。彼らはそれを行うことができないので、彼らがやるだろうと、いくつかの質問に開いている - 彼らは単にエラーを0/1、または1/0、または1/2、または2/1を生産する、または可能性(最良の場合)かもしれませんメッセージます。

これはコンパイラに依存し、ランタイムに依存する場合もあります。コンパイラは、ファイル内の最初の変数がアクセスされるとき、または各変数がアクセスされるときに、静的変数を遅延初期化することを決定する場合があります。それ以外の場合は、起動時にファイルごとにすべての静的変数が初期化されます。その順序は通常、ファイルのリンク順序に依存します。ファイルの順序は、依存関係やその他のコンパイラに依存する影響に基づいて変更される可能性があります。

静的変数は、定数初期化子がない限り、通常はゼロに初期化されます。繰り返しますが、これはコンパイラに依存します。したがって、これらの変数の 1 つは、もう 1 つが初期化されるときにおそらくゼロになります。ただし、どちらにも初期化子があるため、一部のコンパイラでは値が未定義のままになる場合があります。

最も可能性の高いシナリオは次のとおりだと思います。

  1. 変数にはスペースが割り当てられ、両方の値は 0 になります。
  2. 1 つの変数、たとえば x が初期化され、値 1 に設定されます。
  3. もう一方、たとえば y は初期化され、値 2 に設定されます。

いつでも実行して確認できます。一部のコンパイラは、無限ループに入るコードを生成する可能性があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top