2012-02-08 14 views
8

次の声明は何を意味していますか?ローカルおよび動的に割り当てられた変数は、ソースファイルがなぜコンパイラはコンパイル時にローカル変数のアドレスを知りませんか?

をコンパイル時にコンパイラによって知られていないアドレスは、私は、ローカル変数はコンパイル時にアドレスが割り当てられていることを考えるために使用されるが、このアドレスはできてい

範囲外になると変更され、関数呼び出し中に再びスコープに入ります。しかし、上記の文は、ローカル変数のaddresessは、コンパイラによって知られていないと述べています。次に、ローカル変数はどのように割り当てられますか?コンパイル時にグローバル変数のアドレスを知ることができるのはなぜですか?

また、ローカル変数やその他がどのように割り当てられているかを読む良いリンクを提供してください。

ありがとうございます!

+5

OSによってプログラムがロードされ、MMUに仮想メモリマッピングが設定されるまで、アドレスがわからないことがあります。コンパイラはレイアウトを知っています。レイアウトは物事が現れる順序ですが、すべてが基本アドレスから測定されます。静的な記憶期間では、バイナリのロードアドレスから測定されます。自動保存期間は、スタックポインタから測定されます。動的記憶域には実行時に決定されるアドレスがありますが、メンバーは動的アドレスからのオフセットで格納されます。 –

+0

@Ben:それは全く別の問題です。 –

答えて

13

上記の引用は正しい - 通常、コンパイラはコンパイル時にローカル変数のアドレスを知らない。つまり、コンパイラはおそらく、ローカル変数が配置されるスタックフレームのベースからのオフセットを知っていますが、コールスタックの深さによっては、実行時に別のアドレスに変換される可能性があります。例として、この再帰的なコード(!方法により、任意のではありませんが、良いコードを意味する)を検討:

int Factorial(int num) { 
    int result; 
    if (num == 0) 
     result = 1; 
    else 
     result = num * Factorial(num - 1); 

    return result; 
} 

パラメータnumに応じて、このコードはそうそこに、いくつかの再帰呼び出しを行うに終わるかもしれませんresultの複数のコピーがメモリに格納され、それぞれが異なる値を保持します。その結果、コンパイラはどこに行くのかを知ることができません。しかし、resultの各インスタンスは、おそらくそれぞれのFactorial呼び出しを含むスタックフレームのベースから同じ量だけオフセットされます。理論的には、コンパイラはこのコードを最適化するような他の処理を行います。resultのコピーは1つのみです。

通常、コンパイラはスタックフレームのモデルを維持し、スタックフレーム内の次の空いている場所を追跡することによってローカル変数を割り当てます。こうすることで、ローカル変数をスタックフレームの先頭に相対的に割り当てることができます。関数が呼び出されると、スタックアドレスとともに、その相対アドレスを使用して、特定のスタックフレーム内のその変数の位置を検索できます。

グローバル変数は、コンパイル時に既知のアドレスを持つことができます。ローカル変数は、プログラム内に常にグローバル変数のコピーが1つ存在するという点で、ローカル変数とは異なります。ローカル変数は、実行の仕方に応じて0回以上存在することがあります。グローバルの1つのユニークなコピーがあるという事実の結果として、コンパイラはアドレスをハードコードすることができます。さらに読書のためとして

、あなたはコンパイラが変数をレイアウトすることができる方法のかなり綿密な治療を希望する場合は、アホ、ラム、セティ、およびウルマンによってCompilers: Principles, Techniques, and Tools, Second Editionのコピーをピックアップすることができます。この本の多くは他のコンパイラ構築テクニックに関係していますが、本書の大部分はコード生成と生​​成されたコードを改善するために使用できる最適化の実装に専念しています。

希望すると便利です。

+5

* automatic *、not * local *( 'static'かもしれません) –

+0

@ BenVoigt-私は同意します。前者の方が一般的で後者は一般的にC/C++にしか適用されないため、「自動」、「静的」、「動的」ではなく、「ローカル」と「グローバル」を学ぶため、 。 – templatetypedef

+0

@templatetypedef:私はあなたを得ると思いますが、user966379の答えでエラーを指摘してください。 "コンパイル時に、ソースコードが機械語コードに変換され、アドレスがわからない"と言いました。上記。 –

0
  1. ダイナミック変数のアドレスは、メモリプールから動的に割り当てられるため、予想される理由で不明です( )。
  2. ローカル変数のアドレスは、 "スタック"メモリ領域にあるため、わかりません。プログラムのスタックワインディング/巻き戻しは、コードフローのランタイム条件に基づいて遅れる可能性があります( )。例えば

void bar(); // forward declare 
void foo() 
{ 
    int i; // 'i' comes before 'j' 
    bar(); 
} 
void bar() 
{ 
    int j; // 'j' comes before 'i' 
    foo(); 
} 
int main() 
{ 
    if(...) 
    foo(); 
    else 
    bar(); 
} 

if条件はtrue又はfalseすることができ、その結果は、実行時にのみ知られています。そのint iまたはint jに基づいて、適切なオフセットでスタック上で行われます。

+0

私はあなたが "ローカル変数アドレスはコンパイル時に知られていません"と答えると思います。しかし、私はなぜアドレスがコンパイラ自体によって知られていないのか尋ねました。 –

1

私の意見では、この文は変数やスコープへの実行時アクセスについては言及していませんが、何か微妙なことを言っていると思います。

ここで重要な点は、「ローカルで動的に割り当てられた」および「コンパイル時間」です。 私は、これらのアドレスはコンパイル時定数として使用できないという声明を信じています。これは、コンパイル時定数として使用できる静的に割り当てられた変数のアドレスとは対照的です。この一例は、テンプレートである:

int main() 
{ 
    static int y; 
    Klass<&y> y_klass; 
} 

を時定数をコンパイル使用する他のコンテキストがかもしれしかし:

template<int *> 
class Klass 
{ 
}; 

int x; 

//OK as it uses address of a static variable; 
Klass<&::x> x_klass; 


int main() 
{ 
    int y; 
    Klass<&y> y_klass; //NOT OK since y is local. 
} 

コンパイルすることはできませんテンプレートのいくつかの追加の制約があるようです使用可能なのは&yです。

と同様に、私はこれが無効であることを期待したい:Pのデータが動的に割り当てられているので

static int * p; 

int main() 
{ 
    p = new int(); 
    Klass<p> p_klass; 
} 

(pは静的であっても)。

+0

'Klass <&y>'は2番目のスニペットでは合法ですが、おそらくあなたのコンパイラは標準を完全に実装していない可能性があります。 "非テンプレート、非テンプレート*テンプレートパラメタ*の* * template-argument *は、" ... "のいずれかでなければならない。静的記憶期間と外部のオブジェクトのアドレスを指定する定数式(5.19)内部リンケージまたは "...(セクション14.3.2' [temp.arg.nontype] ')これは外部リンケージが必要なC++ 03からの大きな変更です。 –

+0

@BenVoigt私はC++ 03モードでコンパイルしていました。私はテンプレートの制限のいくつかがC++ 11で縮小されているのを見てうれしいです。 –

0

いい質問です。

コードを実行しているときに、プログラムがメモリにロードされます。次に、ローカル変数がアドレスを取得します。コンパイル時に、ソースコードは機械語コードに変換されて実行されます。

関連する問題