3

なぜCはローカル変数を格納するためにスタックを使用するのですか? これは、独立したメモリ空間を持つためですか、それともスコープ外になるとすべてのローカル変数とオブジェクトを自動的にクリアする機能を持つためですか?

同じことについてさらにいくつか質問がありますが、

質問 1) ローカル変数は命令部分からどのように参照されますか。NewThreadFunccreateThread 関数によって呼び出される関数を考慮してください。

DWORD WINAPI NewThreadFunc(PVOID p_pParam)
{
int l_iLocalVar1 = 10;
int l_iLocalVar2 = 20;

int l_iSumLocalVar = l_iLocalVar1 + l_iLocalVar2;
}

このスレッドのスタックは次のようになります。

| p_pParam       |
| NewThreadFunc()|
| 10             |
| 20             |
| 30             |
|                |
.
.
.

l_iSumLocalVarさて、私の質問は、この関数を実行しているときに、CPU がローカル変数 ( 、l_iLocalVar1およびl_iLocalVar2)のアドレスをどのように知るかということです。これらの変数は、値をフェッチする必要があるアドレスを格納するポインターではありません。私の質問は、上記のスタックに関するものです。

質問 2) この関数がさらに他の関数を呼び出した場合、スタックはどのように動作しますか? 私が知っているように、スタックはさらに分割されます。これが真の場合、呼び出し先関数のローカル変数が呼び出された関数から隠される方法。基本的に、ローカル変数がスコープ ルールを維持する方法は?

これらが非常に基本的な質問である可能性があることは知っていますが、これらに対する答えを思いつかない方法もあります。

4

4 に答える 4

6

まず、ローカル変数にスタックを使用するのは「Windows」ではありません。「Windows」やその他のOSとはまったく関係ありません。それを行うのはコンパイラです。その目的でコンパイラにシステム スタックの使用を強制する人は誰もいませんが、通常、これはローカル変数を実装する最も簡単で効率的な方法です。

第二に、スタックのようなストレージはローカル変数の言語で義務付けられたセマンティクスと非常に正確に一致するため、コンパイラはローカル変数 (システム提供のスタックまたはコンパイラ実装スタック) を格納するためにスタックを使用します。ローカル変数の保存期間は、互いに厳密に入れ子になっている宣言領域 (ブロック) によって定義されます。これはすぐに、ローカル変数の保存期間が LIFO の原則 (後入れ先出し) に従うことを意味します。したがって、スタック (LIFO データ構造) を使用して LIFO ストレージ期間を持つオブジェクトを割り当てることは、頭に浮かぶ最初の最も自然なことです。

ローカル変数は通常、現在アクティブなスタック フレームの先頭からのオフセットによってアドレス指定されます。コンパイラは、コンパイル時に各ローカル変数の正確なオフセットを認識しています。コンパイラは、次の方法で現在の関数にスタック フレームを割り当てるコードを生成しますR1。関数のすべてのローカル変数を格納するために必要な量。スタック フレームがこの方法で割り当てられると、ローカル変数l_iLocalVar1は、単にアドレスを介してアクセスされます。l_iLocalVar2l_iSumLocalVarR1 + 6R1 + 10R1 + 14(任意のオフセットを使用しました)。つまり、これらのアドレスはコンパイル時に認識されないため、ローカル変数は特定のアドレス値によってアクセスされません。代わりに、計算されたアドレスを介してローカル変数にアクセスします。それらは、実行時のベースアドレス値 + コンパイル時のオフセット値として計算されます。

于 2013-07-07T18:26:27.997 に答える
3
  1. 通常、システム呼び出し規則は、レジスタを「スタック ポインタ」として使用するために予約しています。ローカル変数へのアクセスは、このレジスタの値に対して相対的に行われます。すべての関数は使用するスタック スペースの量を認識している必要があるため、コンパイラはコードを発行して、各関数の要件に合わせてスタック ポインターが正しく調整されるようにします。

  2. ローカル変数のスコープは、コンパイラによってのみ強制されます。これは、言語構造であり、ハードウェアとは関係がないためです。スタック変数のアドレスを他の関数に渡すことができ、それらは正しく機能します。

于 2013-07-07T17:07:25.213 に答える
0

すべての変数アドレスは、関数呼び出しまたは戻りごとにインクリメントされるスタック ポインターに相対的です。これらの変数によって使用されるメモリを割り当ててクリーンアップするための高速で簡単な方法。

于 2013-07-07T17:09:07.900 に答える