36

私の考えでは、常に、定義はストレージの割り当てを意味します。

次のコードでは、int iプログラムスタックに4バイト(通常)のストレージを割り当ててにバインドしii = 3そのストレージに3を割り当てます。ただし、のためにgoto、定義はバイパスされます。これは、に割り当てられたストレージがないことを意味しiます。

f()ローカル変数は、それらが存在する関数のエントリ(この場合)または定義のポイントのいずれかで割り当てられると聞きました。

iしかし、いずれにしても、まだ定義されていない(ストレージがまったくない)ときにどのように使用できますか?実行時に値3はどこに割り当てられi = 3ますか?

void f()
{
    goto label;
    int i;

label:
    i = 3;
    cout << i << endl; //prints 3 successfully
}
4

8 に答える 8

44

短編小説; goto結果として実行時のジャンプが発生し、変数の定義/宣言によってストレージの割り当てとコンパイル時間が発生します。

コンパイラは、に割り当てるストレージの量を確認して決定します。また、「ヒット」したときにintこの割り当てられたストレージが設定されるようにします。3i = 3;

gotoそのメモリ位置は、例のように、関数の開始時、宣言/定義の前にある場合でも存在します。


非常に愚かな直喩

私が丸太を地面に置き、友人が(目を閉じて)走って飛び越えた場合、丸太はまだそこにあります-たとえ彼がそれを見たり感じたりしていなくても。

彼が望むなら、彼は(後で)振り返ってそれを火にかけることができると言うのは現実的です。彼のジャンプはログを魔法のように消えさせることはありません。

于 2011-12-16T14:44:48.010 に答える
16

あなたのコードは大丈夫です。変数は、そこにいなかったらどこに住んでいたとしても住んでいgotoます。

宣言を飛び越えることができない状況があることに注意してください:

C ++116.7宣言ステートメント[stmt.dcl]

3ブロックに転送することは可能ですが、初期化で宣言をバイパスする方法ではできません。自動保存期間を持つ変数がスコープ内にないポイントからスコープ内にあるポイントにジャンプするプログラムは、変数がスカラー型、単純なデフォルトコンストラクターと単純なデストラクタを持つクラス型を持たない限り、形式が正しくありません。これらのタイプの1つのcv修飾バージョン、または前述のタイプの1つの配列であり、初期化子なしで宣言されます(8.5)。[ 例:

void f()
{
    // ...
    goto lx;    // ill-formed: jump into scope of `a'
    // ...
ly:
    X a = 1;
    // ...
lx:
    goto ly;    // ok, jump implies destructor
                // call for `a' followed by construction
                // again immediately following label ly
}

—例を終了]

于 2011-12-16T14:47:49.723 に答える
9

定義は実行可能コードではありません。これらはコンパイラーへの単なる指示であり、変数のサイズとタイプをコンパイラーに知らせます。この意味で、定義はgotoステートメントによってバイパスされません。

の代わりにコンストラクターを使用してクラスを使用する場合、コンストラクターintの呼び出しは。によってバイパスされますgotoが、ストレージはとにかく割り当てられます。ただし、クラスインスタンスは初期化されないままになるため、定義/初期化行がコントロールを取得する前に使用するとエラーになります。

于 2011-12-16T14:44:49.787 に答える
8

私の考えでは、常に、定義はストレージの割り当てを意味します。

これは正しくありません。変数のストレージは、関数のスタックレイアウトを作成するときにコンパイラーによって予約されます。はgoto初期化をバイパスするだけです。印刷する前に値を割り当てるので、すべて問題ありません。

于 2011-12-16T14:43:42.533 に答える
2

フローの制御は、コンパイル時にコンパイラーによって予約されている変数のストレージとは何の関係もありません。

このgotoステートメントは、オブジェクトの動的初期化にのみ影響します。組み込み型とPOD型の場合、初期化されないままになる可能性があるため、問題ではありません。ただし、非PODタイプの場合、これによりコンパイルエラーが発生します。たとえば、これを参照してください

struct A{ A(){} };  //it is a non-POD type

void f()
{
    goto label;

    A a;     //error - you cannot skip this!

label:
    return;
}

エラー:

prog.cpp: In function ‘void f()’:
prog.cpp:8: error: jump to label ‘label’
prog.cpp:5: error:   from here
prog.cpp:6: error:   crosses initialization of ‘A a’

ここを参照してください:http://ideone.com/p6kau

この例では、ユーザー定義のコンストラクターがあるためA、非PODタイプです。つまり、オブジェクトを動的に初期化する必要がありますが、ステートメントはこれをスキップしようとするため、コンパイラーはエラーを生成します。goto

組み込み型とPOD型のみのオブジェクトは初期化されないままになる可能性があることに注意してください。

于 2011-12-16T14:51:17.627 に答える
1

簡単に言うと、変数宣言は字句です。つまり、字句で囲まれた{}ブロックに関係します。バインディングは、宣言された行からブロックの終わりまで有効です。フロー制御()の影響を受けませんgoto

一方、locol(スタック)変数の変数割り当ては、制御フローがそこに到達したときに実行される実行時操作です。だからそれgotoに影響を与えます。

オブジェクトの構築が関係するようになると、物事は少しトリッキーになりますが、ここではそうではありません。

于 2011-12-16T14:44:53.173 に答える
1

の宣言の位置はi、コンパイラーとは無関係です。int iこれは、コードを前gotoと後でコンパイルし、生成されたアセンブリを比較することで証明できます。

g++ -S test_with_i_before_goto.cpp -o test1.asm
g++ -S test_with_i_after_goto.cpp -o test2.asm
diff -u test1.asm test2.asm

この場合の唯一の違いは、ソースファイル名(.file)参照です。

于 2011-12-16T14:50:03.133 に答える
0

変数の定義は、変数にメモリを割り当てません。ただし、変数を格納するための適切なメモリスペースを準備するようにコンパイラに指示しますが、制御が定義を通過したときにメモリは割り当てられません。

ここで本当に重要なのは初期化です。

于 2011-12-16T14:46:39.817 に答える