次のコード例が何をし、どのようにそれを行うのか理解できません。
_#include <stdio.h>
int f();
int a = f(); // a exists just to call f
int x = 22;
int f() {
++x;
return 123; // unimportant arbitrary number
}
int main() {
printf("%d\n", x);
}
_
これを実行すると、_23
_が出力されます。これは直感的な答えです。
ただし、C++では、グローバル変数は 想定 定義順に初期化されます。 a
の前に定義されているため、x
の前にx
を初期化する必要があることを意味します。その場合、f
への呼び出しはx
の一部であるため、f
が初期化される前に関数a
を呼び出す必要があります。定義。
f
が初期化される前にx
が実際に呼び出された場合、それはf
がx
をインクリメントしようとすることを意味します。確かに(ほとんどの場合UB、または何らかの意味不明な値)。次に、a
が初期化された後、x
は_22
_に初期化され、プログラムは_22
_を出力します。
明らかにそれは起こりません。しかし、何をしますか?そのコードは実際に何をしますか?
a = f()
が評価される前にx
が_22
_に設定されているように見えますが、それは初期化の順序が逆になっていることを意味します(初期化とは間違っている可能性もあります) 、または発生した場合)。
問題は少し微妙です。詳細については、C++ 11 3.6.2を参照してください。
私たちにとって重要なのは、「静的ストレージ期間を持つ非ローカル変数」(または口語的な用語では「グローバル変数」)の初期化の2つのフェーズがあることです:静的初期化フェーズおよび動的初期化フェーズ。静的フェーズが最初になります。次のようになります。
int a = 0;
int x = 22;
その後、動的初期化が実行されます。
a = f();
ポイントは、静的初期化はまったく「実行」されないということです-コンパイル時に既知の設定値のみで構成されるため、実行前にこれらの値はすでに設定されています。初期化の理由int x = 22;
staticは、初期化子が定数式であることです。
動的な初期化mayが静的な段階に引き上げられる場合があります(ただし、そうである必要はありません)が、これはこれらの場合の1つではありません。
初期化の動的バージョンは、初期化の前に名前空間スコープの他のオブジェクトの値を変更しません
この巻き上げが発生した場合、結果の初期値は、発生しなかった場合と異なる場合があります。このような「不定」初期化の1つの例が標準にあります。
また、考慮してください:
_#include <iostream>
using namespace std;
int f();
int g();
int a = f();
int b = g();
int main() {
cout << a << " " << b;
}
int f() {
b++;
cout << "f" << endl;
return 1;
}
int g() {
cout << "g" << endl;
return 2;
}
_
出力は次のとおりです。
_f
g
1 2
_
b = g();
を_b = 22;
_に置き換えると、_1 23
_が出力されます。 Kerrek SBの答えは、これがなぜなのかを説明しています。