3

私はこの記事を読んでいて、これを見ました:「この記事は、少なくとも基本的にGNU/Linuxシステムのメモリマップがどのように機能するか、特にスタックに静的に割り当てられたメモリと動的に割り当てられたメモリの違いをすでに知っていて理解していることを前提としています。ヒープ。"

スタックとヒープは動的に割り当てられる、つまり必要な場合にのみ割り当てられ、グローバル変数と関数内で「静的」として宣言された変数は静的に割り当てられる、つまり常に割り当てられると思っていたので、これは私を混乱させました。

たとえば、私が持っている場合

void f() {
    int x = 1;
    ...
}

値 1 のみがスタックに置かれ、関数 f() が呼び出された場合にのみスタック ポインターがインクリメントされます。同様に、私が持っている場合

void f() {
    int x = malloc(1 * sizeof(int));
    ...
}

そのヒープメモリは、f() が呼び出された場合にのみ割り当てられます。ただし、「int x = 1;」がある場合 プログラムのグローバル セクションまたは「static int x = 1;」関数本体内では、このプログラムを実行するたびに、そのメモリが値 1 のデータ セクションに割り当てられます。

私はこれについて間違っていますか?

4

3 に答える 3

4

初期化ステートメントが関数本体内にある場合でも、静的変数は一度だけ初期化されます。

ウィキペディアの例を確認してください:

#include <stdio.h>

void func() {
    static int x = 0; 
    /* x is initialized only once across five calls of func() and
      the variable will get incremented five 
      times after these calls. The final value of x will be 5. */
    x++;
    printf("%d\n", x); // outputs the value of x
}

int main() { //int argc, char *argv[] inside the main is optional in the particular program
    func(); // prints 1
    func(); // prints 2
    func(); // prints 3
    func(); // prints 4
    func(); // prints 5
        return 0;
}

スタックは基本的に、静的に割り当てられた大きな配列であり、その先頭から移動可能なポインターが開始されます。関数を呼び出すと (main から開始)、ポインターが移動し (スタック フレームを作成)、スタック フレーム内のスペースがスライスされてローカル変数に割り当てられます (ローカル変数の数によって、関数のスタック フレームの大きさが決まります)。になります)。したがって、ローカル変数は一種の動的 (関数に入ったときにのみ現れる) ですが、スタックは静的サイズです。超大規模な構造体を割り当てたり、再帰を使いすぎたりすると、スタックオーバーフローと呼ばれる現象が発生し、OS によって停止されます。(スタック オーバーフロー アイコンアイコンは実際にこれを示しています。下部にある灰色のコンテナーは、スタックである静的配列を表します。オレンジ色の長方形は、関数呼び出しによって作成されたフレームです。適切なスタック オーバーフローの場合と同様に、フレームがコンテナーをオーバーフローして爆発します。つまり、プログラムは死んでいます。フレームが上昇するという事実は、スタックに関するもう 1 つのかなり特殊なことを示しています。新しいフレームは古いフレームよりもアドレスが低いため、スタックオーバーフローは実際にはスタック配列の最後ではなく先頭で発生します (配列を次のように考えない限り)。最大のインデックスから始まり、0 で終わります)。)

于 2015-10-10T17:40:34.243 に答える
2

スタックはスタックフレーム単位で割り当てられます。

  • 関数が呼び出されると、スタック フレームが割り当てられます。
  • 関数が戻ると、そのスタック フレームが消え、

また、スタックは関数の引数とローカル変数を保存するのに役立ちます。

関数がスタック フレームを取得した後、はい、スタック フレーム内で、関数は動的に必要なバイトを使用します。


ヒープのような動的割り当てスタック

ヒープのようにスタックにメモリを割り当てたい場合は、alloca()fromを使用できます<alloca.h>。ヒープよりも高速ですが、ほとんどの場合、それは必要ありません。欠点があるため、一般的には推奨されません。


別のコンテキストでスタック割り当てを説明すると、より明確になる可能性があります。

  • Linux の観点からthread(ちなみに、各プロセスにはデフォルトで作成時にメインスレッドとして 1 つのスレッドがあります)、スタックは固定サイズであり、スレッド作成時に割り当てられます (IA-32 の場合は 2Mb、IA-32 の場合は 32Mb)。デフォルトでは 64)、必要に応じてデフォルトのサイズを変更できます。したがって、これは修正され、静的であると言えます。
  • functionスレッドまたはプロセス内から見ると、関数の開始時にスレッドのスタック メモリからスタック フレームが割り当てられ、関数の終了時にスタック フレームが消えます。
  • local variable関数内の非静的の観点から、変数は必要に応じて関数のスタック フレームから動的に割り当てられます。

したがって、それを静的または動的と呼ぶ必要があるかどうかは、あなたが決めてください。

于 2015-10-10T17:39:24.200 に答える