回答:
スタックフレームは、スタックにプッシュされるデータのフレームです。呼び出しスタックの場合、スタックフレームは関数呼び出しとその引数データを表します。
私の記憶が正しければ、関数の戻りアドレスが最初にスタックにプッシュされ、次にローカル変数の引数とスペースがプッシュされます。これらは一緒になって「フレーム」を作りますが、これはおそらくアーキテクチャに依存します。プロセッサは各フレームのバイト数を認識しており、フレームがスタックからプッシュおよびポップされると、それに応じてスタックポインタを移動します。
上位レベルの呼び出しスタックとプロセッサの呼び出しスタックの間には大きな違いがあります。
プロセッサのコールスタックについて話すときは、アセンブリコードまたはマシンコードでバイト/ワードレベルのアドレスと値を操作することについて話しています。高水準言語について話すときは「コールスタック」がありますが、これらはランタイム環境によって管理されるデバッグ/ランタイムツールであり、プログラムで発生した問題を(高レベルで)ログに記録できます。このレベルでは、行番号、メソッド名、クラス名などがよく知られています。プロセッサがコードを取得するまでには、これらの概念はまったくありません。
スタックをよく理解していれば、プログラムでメモリがどのように機能するかを理解し、プログラムでメモリがどのように機能するかを理解すれば、プログラムでの関数ストアの方法を理解し、プログラムでの関数ストアの方法を理解すれば、再帰関数の機能と再帰関数がどのように機能するかを理解し、コンパイラがどのように機能するかを理解し、コンパイラがどのように機能するかを理解すれば、コンパイラとして機能し、プログラムを非常に簡単にデバッグできます。
スタックの仕組みを説明しましょう:
最初に、関数がスタックでどのように表されるかを知る必要があります。
ヒープには、動的に割り当てられた値が格納されます。
Stackは、自動割り当てと削除の値を保存します。
例で理解しましょう:
def hello(x):
if x==1:
return "op"
else:
u=1
e=12
s=hello(x-1)
e+=1
print(s)
print(x)
u+=1
return e
hello(4)
このプログラムの一部を理解してください:
スタックとは何か、スタックパーツとは何かを見てみましょう。
スタックの割り当て:
1つの点に注意してください。ローカル変数がロードされているかどうかに関係なく、関数の戻り条件が満たされると、関数はそのスタックフレームとともにスタックからすぐに戻ります。つまり、再帰関数が基本条件を満たし、基本条件の後にリターンを置くと、基本条件はプログラムの「else」部分にあるローカル変数のロードを待機しません。スタックから現在のフレームがすぐに返され、その後、次のフレームがアクティブ化レコードに追加されます。
実際にこれを見てください:
ブロックの割り当て解除:
したがって、関数がreturnステートメントに遭遇すると、現在のフレームがスタックから削除されます。
スタックから戻る際、スタックに割り当てられた元の順序とは逆の値が返されます。
hello()
が再帰的に呼び出されhello()
たため、3つのスタックフレームがhello()
あり、グローバルフレームは最初の関数を呼び出した元の関数hello()
ですか?
簡単にまとめます。多分誰かがより良い説明をしています。
呼び出しスタックは、1つまたは複数のスタックフレームで構成されます。各スタックフレームは、リターンでまだ終了していない関数またはプロシージャの呼び出しに対応しています。
スタックフレームを使用するために、スレッドは2つのポインターを保持します。1つはスタックポインター(SP)と呼ばれ、もう1つはフレームポインター(FP)と呼ばれます。SPは常にスタックの「トップ」を指し、FPは常にフレームの「トップ」を指します。さらに、スレッドは、実行される次の命令を指すプログラムカウンター(PC)も保持します。
スタックには、ローカル変数と一時変数、現在の命令の実際のパラメーター(手順、関数など)が格納されます。
スタックのクリーニングに関しては、さまざまな呼び出し規約があります。
「コールスタックはスタックフレームで構成されています...」- ウィキペディア
スタックフレームは、スタックに置くものです。これらは、呼び出すサブルーチンに関する情報を含むデータ構造です。
プログラマーは、スタックフレームについて幅広い用語(1つの関数呼び出しのみを提供し、戻りアドレス、引数、およびローカル変数を保持するスタック内の単一のエンティティ)ではなく、狭い意味で質問があります–用語stack frames
がコンパイラオプションのコンテキスト。
質問の作成者が意図したものかどうかは関係ありませんが、コンパイラオプションの観点から見たスタックフレームの概念は非常に重要な問題であり、ここでは他の回答では扱いません。
たとえば、Microsoft Visual Studio 2015 C / C ++コンパイラには、に関連する次のオプションがありますstack frames
。
GCCには次のものがあります。
インテルC ++コンパイラーには次のものがあります。
次のエイリアスがあります:
Delphiには、次のコマンドラインオプションがあります。
その特定の意味では、コンパイラーの観点から、スタックフレームは、アンカーをスタックにプッシュするルーチンの入り口と出口のコードにすぎません。デバッグや例外処理にも使用できます。デバッグツールはスタックデータをスキャンし、これらのアンカーを使用call sites
してスタック内を検索します。つまり、階層的に呼び出された順序で関数の名前を表示します。Intelアーキテクチャーの場合、これはpush ebp; mov ebp, esp
またはenter
エントリー用mov esp, ebp; pop ebp
またはleave
出口用です。
コンパイラがこのコードを生成するかどうかを制御できるため、コンパイラオプションに関しては、スタックフレームが何であるかをプログラマが理解することが非常に重要です。
場合によっては、スタックフレーム(ルーチンのエントリコードと終了コード)をコンパイラで省略でき、変数には、便利なベースポインタ(BP /ではなく、スタックポインタ(SP / ESP / RSP)を介して直接アクセスします。 ESP / RSP)。スタックフレームの省略の条件。例:
スタックフレーム(ルーチンのエントリコードと終了コード)を省略すると、コードが小さくて高速になりますが、スタック内のデータをバックトレースしてプログラマーに表示するデバッガーの機能に悪影響を与える可能性もあります。これらは、関数がエントリコードと終了コードを持つ条件を決定するコンパイラオプションです。たとえば、(a)常に、(b)決して、(c)必要な場合(条件を指定)です。
スタックフレームは、関数呼び出しに関連するパックされた情報です。この情報には通常、関数に渡される引数、ローカル変数、終了時に戻る場所が含まれます。アクティベーションレコードは、スタックフレームの別名です。スタックフレームのレイアウトはABIでメーカーによって決定され、ISAをサポートするすべてのコンパイラはこの標準に準拠する必要がありますが、レイアウトスキームはコンパイラに依存する場合があります。一般的にスタックフレームのサイズは制限されていませんが、「レッド/保護ゾーン」と呼ばれる概念があり、システムコールなどをスタックフレームに干渉することなく実行できます。
常にSPがありますが、一部のABI(ARMやPowerPCなど)では、FPはオプションです。スタックに配置する必要がある引数は、SPのみを使用してオフセットできます。スタックフレームが関数呼び出し用に生成されるかどうかは、引数のタイプと数、ローカル変数、ローカル変数への一般的なアクセス方法によって異なります。ほとんどのISAでは、最初にレジスタが使用され、引数を渡すための専用レジスタよりも引数が多い場合、それらはスタックに配置されます(たとえば、x86 ABIには整数引数を渡すための6つのレジスタがあります)。したがって、一部の関数では、スタックにスタックフレームを配置する必要がなく、戻りアドレスがスタックにプッシュされるだけです。