11

(英語が下手でごめんなさい。)

質問1。

void foo(void)
{
    goto inside;
    for (;;) {
        int stack_var = 42;
inside:
        ...
    }
}

ラベルに移動したstack_varときに割り当てられるスタック内の場所になりますか?つまり、変数insideを正しく使用できますか?stack_var...

質問2。

void foo(void)
{
    for (;;) {
        int stack_var = 42;
        ...
        goto outside;
    }
outside:
    ...
}

私がレーベルstack_varに行くとき、割り当て解除のスタックの場所になりますか?たとえば、内でoutside行うのは正しいですか?return...

言い換えれば、gotoスタック変数を正しく操作するのに賢いのでしょうか(ブロックをウォークスルーするときの自動(割り当て解除))、それとも単なるばかげたジャンプですか?

4

2 に答える 2

10

質問1:

...内でstack_var変数を正しく使用できますか?

... のコードは に書き込むことができますstack_var。ただし、実行フローが初期化を飛び越えたため、この変数は初期化されていません。

C99 標準から、6.8:3

自動保存期間 […] を持つオブジェクトの初期化子が評価され、値がオブジェクトに保存されます (初期化子のないオブジェクトに不確定な値を保存することを含む) 実行の順序で宣言に到達するたびに

私のコンパイラは、以下の関数をアセンブリの一部にコンパイルします。アセンブリは、初期化されていない内容を返すことがありますx

int f(int c){
  if (c) goto L;
  int x = 42;
 L:
  return x;
}

    cmpl    $0, %eax
    jne LBB1_2
    movl    $42, -16(%rbp)
LBB1_2:
    movl    -16(%rbp), %eax
...
    popq    %rbp
    ret

質問2:

外部ラベルに移動すると、stack_var の割り当てが解除されたスタック内の場所になりますか?

stack_varはい、変数がスコープ外になるとすぐに、予約されたメモリが再利用されることが期待できます。

于 2012-11-11T10:05:53.023 に答える
2

2 つの異なる問題があります。

  • Cコード内の変数のレキシカル スコープ。C変数は、それが宣言されているブロック内でのみ意味を持ちますコンパイラが変数の名前をスコープ ブロック内でのみ意味を持つ一意の名前に変更していると想像できます。

  • 生成されたコードでフレームを呼び出します。優れた最適化コンパイラは通常、現在の関数の呼び出しフレームをマシン クラス スタックの関数の先頭に割り当てます。スロットと呼ばれるその呼び出しフレーム内の特定の場所は、コンパイラによっていくつかのローカル変数 (または他の目的) に再利用できます (通常は再利用されます)。

また、ローカル変数はレジスターにのみ保持でき (呼び出しフレームにスロットはありません)、そのレジスターは明らかにさまざまな目的で再利用されます。

おそらく、最初のケースで未定義の動作が発生している可能性があります。の後は初期化さgoto insideれてstack_varいません。

gcc -Wall警告が表示されなくなるまで、コードをコンパイルして改善することをお勧めします。

于 2012-11-11T10:05:53.373 に答える