3

C では、関数はいつ割り当てられ、メモリ内のどこに移動しますか?

関数のメモリは、プログラムが最初にコンパイルされたときに割り当てられますか、それとも関数呼び出しが最初に表示されたときに割り当てられますか? スタックまたはコードセグメントに割り当てられていますか?

4

3 に答える 3

3

あなたの質問は良い質問ですが、コードを実行している CPU のむき出しのトランジスタに触れるものがあるため、さらに複雑になることを覚悟しておいてください...

4種類に凝縮しようとして惨めな失敗をする。

  • グローバルストレージ
  • コード収納
  • ローカルストレージ
  • 動的ストレージ

コード ストレージは非常に単純なはずなので、少し複雑にします。手続き型言語スニペットに変換された一連の思考 (以降「関数」と呼びます) が、一連の機械語命令に変換されました。

それらはプロセッサによってフェッチされて実行される必要があるため、コード記憶領域を定義する ROM または RAM に配置する必要があります。関数が複数回または再帰的に呼び出された場合でも、そのコードのインスタンスは 1 つしかありません。

(インライニングには入らないようにしましょう)


グローバル データ ストレージは、関数内外で宣言されたすべての変数 (宣言ごとに 1 つのインスタンスのみ) が有効になる RAM と、静的として宣言された変数 (関数内または関数外) です。これらは、絶対 (または準) アドレスによって参照されます。

定数は、独自の ROM ストレージ領域を取得する場合と取得しない場合があります...そのコンパイラ/最適化に固有です。


関数のローカルストレージは、引数/戻り値の受け渡しとローカル変数 (その中で宣言されているため、それによってのみ表示される) のバッグであり、各呼び出しが個別のコンテキストを取得できるように、関数へのすべての呼び出しには個別のバッグが必要です。

通常 (記憶に残る例外があります)、Call-Stack メカニズムを使用して、各関数呼び出しが生成するいくつかのローカル ストレージ領域を積み上げます。不確実性が増していますが、これはメモリ アドレスのデクリメントで成長するスタック フレームであることがわかります。

したがって、ローカル ストレージは、コンパイラの関数呼び出しコード (自動的に実行されます) が関数の引数、呼び出された関数の戻りプレースホルダー、呼び出し関数の戻りアドレス、およびすべての非静的 (および最適化されたもの) を配置する場所です。内部レジスター使用法) 変数。呼び出しごとに 1 つ。これらのローカル変数と引数が参照される関数コードは、...エラー.. スタック ポインタとオフセット、つまり現在のスタック フレームの終了アドレスを指す CPU レジスタを介して後者を参照します (関数コードはどうすればよいでしょうか)。それ以外の場合はメモリアドレスを知っていますか?)。

関数を呼び出すには、そのローカル ストレージを設定し、最終的に引数をそこにコピー (スタックにプッシュ) し、いくつかのローカルを初期化してから、関数コードにジャンプします。戻るとは、呼び出された関数の戻り値を呼び出し元関数のローカル ストレージにコピーし、呼び出された F のローカル ストレージを破棄し、スタック ポインターを以前に山積みされたローカル ストレージ バッグの最後に配置し、保存された呼び出し元の次の命令アドレスにジャンプすることです (物事を飛び出す)。すべて完了。

単一の C プロセスのメモリ スナップショットを見ると、特定のプログラムが実行する関数呼び出し/戻りパターンに従ってブロックが拡大および縮小する、いくつかの積み上げられたローカル ストレージ領域を含むスタックを作成できます。


動的メモリは一般に、malloc と free によって管理されます。これは、ポインタを介してアクセスするメモリ ブロックの成長するアドレス スタックのキーパーです。これにより、間違った名前のヒープ領域が形成されます (時間の経過とともに、ヒープではなくスイス チーズが得られる可能性が高いため)。

これらのメモリ チャンクはあらゆる目的に使用できます。課題は、解放するのを忘れないようにすることです。そうしないと、時間内にコール スタックに「リーク」します (それがどれほど破壊的であるかは簡単にわかります)。

malloc/free によって管理される動的メモリを使用するには、少し余分な規律が必要ですが、巨大なローカル ストレージまたは無駄なグローバル ストレージを回避するのに非常に役立ちます (関数が大量のデータを処理する必要があり、数回呼び出される可能性がある状況では、または、メモリ内に存在する必要がほとんどない大きなデータ チャンク)。

Dyn メモリ領域は、通常、グローバルとスタックの間に挟まれています...一部の組み込みコンパイラでは、2 つのサイズを指定できます。

動的メモリを管理する方法は malloc と free だけではありません。私は現在、free() を必要としない独自の逆参照アロケータを使用しています。規律のないコードと漏れのない.... yaayy!

于 2012-07-10T09:32:09.867 に答える
2

C関数のメモリは、関数がメモリにロードされるときに常にコードセグメントから割り当てられます。関数がダイナミックリンクライブラリに属している場合、プログラムは任意の時間に関数をロードおよびアンロードできます。

于 2012-07-10T04:28:20.357 に答える