チュートリアルでそれは言った
gotoステートメントを使用してブロックの途中にジャンプすると、そのブロック内の自動変数は初期化されません。
次に、以下のコードで、アクセス/宣言できる場合、なぜ初期化されないのですか?
int main()
{
goto here;
{
int i=10;
here:
printf("%d\n",i);
}
return 0;
}
ps:outputはごみの値です。
チュートリアルでそれは言った
gotoステートメントを使用してブロックの途中にジャンプすると、そのブロック内の自動変数は初期化されません。
次に、以下のコードで、アクセス/宣言できる場合、なぜ初期化されないのですか?
int main()
{
goto here;
{
int i=10;
here:
printf("%d\n",i);
}
return 0;
}
ps:outputはごみの値です。
i
「アクセスできるのなら、なぜ...」という質問の背後に論理はありません。「アクセスi
」できることは、何に対しても賛成でも反対でもありません。これは、printf
ステートメントがと同じスコープ内にあることを意味しi
ます。ただし、初期化子を飛び越えたため、変数は初期化されていません(チュートリアルで説明されているとおり)。
初期化されていない変数の読み取りは未定義の動作であるため、プログラムの形式が正しくありません。
変数は内部ブロック内に存在することがわかっているため、変数のメモリはi
コンパイル時にすでに確保されています。ご想像のとおり、メモリは動的に割り当てられません。すでに存在しますが、が原因で決定的なものに設定されることはありませんgoto
。
経験則:初期化子を飛び越えないでください。
変数は、{}
そのスコープ内のステートメントの実行順序に関係なく、宣言されたスコープ(この場合はの間)に表示されます。のgoto
初期化をバイパスします。つまり、が呼び出されi
たときに値が未定義になります。printf()
別の明白な状況を考えてみましょう。
int main()
{
int i; //i is declared, but not initialized
goto here;
{
i=10;//i is initialized
here: //you've skipped the initialization
printf("%d\n",i);//and got garbage
}
return 0;
}
あなたの場合:
int main()
{
goto here;
{
//printf("%d\n",i); // i does not exist here yet
int i; //from here until the end of the scope variable i exists
i=10; // i exists here and smth is written into it
here: // i exists here
printf("%d\n",i); // i exists here and it's value is accessed
}
return 0;
}
だから、int i = 5;
それは本当に2つのことです。1つは宣言であり、次goto
のようなものをスキップすることはできません(新しいスコープを開くことも影響を受けません。スコープの真ん中にジャンプしましたが、スコープはすでに存在していました)。goto
2つ目は操作の割り当てであり、通常の操作(プログラムフロー)であるため、「中断」または「続行」または「戻る」によってスキップできます。
Cコンパイラはソースファイルを解析し、変数の初期化を「記録」します。
届いたら
printf("%d\n", i)
変数iがすでに存在し、スコープ内にあるため、彼はそれを使用できるはずです。
実行時のスペースは、main関数の呼び出し直後、main()のコードが実行される前に、スタック上のi変数用に予約されています。
言語標準がそう言っているので:
6.7.8初期化
セマンティクス
自動保存期間を持つオブジェクトが明示的に初期化されていない場合、その値は不確定です。
J.2未定義動作
次の状況では、動作は定義されていません。
自動保存期間のあるオブジェクトの値は、不確定なときに使用されます。
6.8.4.2switchステートメント
例人工プログラムフラグメント
switch (expr)
{
int i = 4;
f(i);
case 0:
i = 17;
/* falls through into default code */
default:
printf("%d\n", i);
}
識別子がiのオブジェクトは、自動保存期間(ブロック内)で存在しますが、初期化されることはありません。したがって、制御式の値がゼロ以外の場合、printf関数の呼び出しは不確定な値にアクセスします。同様に、関数fの呼び出しには到達できません。
Cを使用すると、実際に初期化されているかどうかに関係なく、アドレス空間内のあらゆるものにアクセスできます。そのように動作すると、クラッシュしたり、ゴミが表示されたり、便利なものが印刷されたりすることがありますが、それはすべて未定義の動作です。便利なトリックですが、プログラムを破るのに最適な方法です。結果を得るだけでトリックが機能するとは思わないでください。