25

私は本から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を取得しますか?または初期化されませんか?
4

4 に答える 4

17

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

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

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

ステップ3:他の変数は動的に初期化され、値を取得します2

于 2010-06-14T07:43:14.260 に答える
15

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

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

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

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

于 2010-06-14T11:34:34.510 に答える
2

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

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

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

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

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

于 2010-06-14T07:11:43.977 に答える
2

要点(そしてそれが「フィアスコ」と呼ばれる理由)は、このような場合にが起こるかを確実に言うことは不可能であるということです。基本的に、あなたは不可能なことを求めています(2つの変数がそれぞれ一方が他方よりも大きいこと)。彼らはそれを行うことができないので、彼らがすることはいくつかの質問に開かれています-彼らは0/1、または1/0、または1/2、または2/1、またはおそらく(最良の場合)単なるエラーを生成する可能性がありますメッセージ。

于 2010-06-14T07:11:53.987 に答える