アドレス空間にスタックが何であるかをよりよく理解したいだけです(つまり、コード/テキスト、ヒープ、データ、およびスタックがあります)
基本的に私の理解では、スタックにはローカル変数が含まれていますが、データに含まれるものとスタックに含まれるものの違いは何ですか?データ変数もそうではありませんか?
プログラムに関数a()への再帰呼び出しがある場合、それは再帰のすべてのレベルに対して新しいスタックがあることを意味しますか?
アドレス空間にスタックが何であるかをよりよく理解したいだけです(つまり、コード/テキスト、ヒープ、データ、およびスタックがあります)
基本的に私の理解では、スタックにはローカル変数が含まれていますが、データに含まれるものとスタックに含まれるものの違いは何ですか?データ変数もそうではありませんか?
プログラムに関数a()への再帰呼び出しがある場合、それは再帰のすべてのレベルに対して新しいスタックがあることを意味しますか?
スタックは通常、使用方法と管理方法のみがデータと異なります。非ローカル変数自体は通常、既知の特定のメモリ位置を持っていますが、スタック上のものはレジスタ(スタックポインタまたはベースポインタなど)に関連して検出されます。
スタックには通常、スタック自体を管理するためのローカル変数、渡されたパラメーター、および制御情報が含まれています。
また、再帰呼び出しを行うと、新しいスタックは取得されず、新しいスタックフレームのみが取得されます。フレームは、現在のスタックの深さに関連するスタックのチャンクです(再帰によるものであれ、通常の関数呼び出しによるものであれ)。これが再帰を可能にするものであり、特定の深度の変数が他の深度の変数から独立しているという事実です。
もちろん、これはすべてアーキテクチャに依存していることに注意してください。上記の私の説明は一般的なケースですが、SPARC、System z、RCA1802など、スタックが異なる方法で実行されるアーキテクチャがあります。
まず、簡単な説明。スタックは必ずしもDRAMにあるとは限りません。これらは、DRAM、キャッシュ、ディスクなど、どのメモリでも形成できる構造にすぎません。
スタックを理解するには、まずスタックとは何かを理解する必要があります。これはトレイのスタックのようなもので、スタックにするプロパティは次のとおりです。
スタックに何かを格納する行為はPUSHと呼ばれ、それを削除する行為はPOPと呼ばれます。空のスタックに対して次のことを行ったとします。
プッシュA プッシュB プッシュC
次に、スタックには次のものが含まれます
C-トップ B A
ここでPOPを実行すると(ここにはオペランドがないことに注意してください)、Cが返され、スタックには次のものが含まれます。
B-スタックの一番上 A
したがって、プロセッサのスタックは、上記のアルゴリズムのハードウェア実装にすぎません。
レジスタには、スタックポイントと呼ばれるスタックの最上位のアドレスが含まれています 。ISA(命令セットアーキテクチャ)は、上で示したように、スタック変数にアクセスするためのPUSHおよびPOP命令を提供します。
これは非常に便利な構成です。スタックは、ローカル変数、基本的には関数呼び出しの最後に削除する一時データを格納するために使用されます。特に関数呼び出しに役立ちます。関数が呼び出されると、新しく呼び出された関数のローカル変数の変数がスタックにプッシュされます。
foo(){
int a;
int b; // both registers containing a and b are PUSHed here on the stack
c = bar(); // pop the stack to get value of c
print c
}
bar(){
int z; // local variables pushed on top of the stack
z = ...
return z; // pop all local variables of bar(), then push z on the stack
}
上記がお役に立てば幸いです。
次のプログラムは、何が起こっているのかを理解するのに役立ちます。テキスト、bss、ヒープ、およびスタックのポインターの例が表示されます。テキストは通常実行可能コードであり、bssは静的/グローバル変数であり、ヒープは動的に割り当てられたメモリであり、スタックにはローカル変数が含まれています。
#include <stdlib.h>
#include <stdio.h>
#define TESTS 10
int numfeed = 0;
int numdead = 0;
recurse(int x)
{
u_int pattern=0xfeedface;
u_int *otherpattern = malloc(4);
*otherpattern = 0xdeadbeef;
printf("Feedface %d is at %p\n",x,&pattern);
printf("deadbeef %d is at %p\n",x,otherpattern);
if (--x == 0)
{
int *off;
for(off = &pattern;numfeed<TESTS;off++)
{
if (*off == 0xfeedface)
printf("Found feedface #%d at %p\n", ++numfeed, off);
if (*off == 0xdeadbeef)
printf("Found deadbeef #%d at %p -- WHAT?!?!!?!?\n", ++numdead, off);
}
}
else
{
recurse(x);
}
// Not freeing otherpattern intentionally.
}
main()
{
u_int *otherpattern = malloc(4);
*otherpattern = 0xdeadbeef;
int *off;
recurse(TESTS);
for(off = otherpattern+1;numdead<TESTS;off++)
{
if (*off == 0xfeedface)
printf("Found feedface #%d at %p -- WHAT?!?!!!?!?\n", ++numfeed, off);
if (*off == 0xdeadbeef)
printf("Found deadbeef #%d at %p\n", 1+TESTS-(++numdead), off);
}
printf("numfeed is at %p\n",&numfeed);
printf("recurse is at %p\n",&recurse);
}