C言語のスタックフレームとは?関数呼び出し時のメモリ構造を図でわかりやすく解説

目次

メモリ領域解説シリーズ

本記事は「メモリ領域解説」シリーズの1つです。

メモリ領域解説シリーズの全体像はこちら

関数を呼び出すと、スタック領域にはどのようなデータが積まれるのでしょうか。

C言語では関数呼び出しのたびに、スタック上に**スタックフレーム(Stack Frame)**と呼ばれる領域が作られます。

このスタックフレームには次のような情報が保存されます。

  • 関数の引数
  • ローカル変数
  • 戻りアドレス
  • 退避されたレジスタ

これを理解すると、

  • なぜ再帰が動くのか
  • なぜローカル変数は関数終了で消えるのか
  • スタックオーバーフローはなぜ起きるのか

といった仕組みが見えてきます。

今回は、C言語の関数呼び出しとスタックフレームの関係を図を使って整理します。

スタック領域の基本はこちらの記事で解説しています。


初心者さん

先輩、スタック領域の記事で“関数呼び出しごとにデータが積まれる”ってありましたよね。
あれって具体的に何が積まれてるんですか?

エンジニアくん

いい質問だね。それがスタックフレームなんだ。

初心者さん

フレーム?

エンジニアくん

関数1回分の作業スペースみたいなもの。
関数が呼ばれると、その関数専用のメモリ領域がスタックに作られるんだ。


スタックフレームとは

スタックフレームとは、関数呼び出し1回分のデータを保存する領域です。

関数が呼び出されると、スタックに新しいフレームが作られます。

main()
 └ funcA()
     └ funcB()

このように関数が呼ばれると、スタックは次のようになります。

+----------------+
| funcB frame    |
+----------------+
| funcA frame    |
+----------------+
| main frame     |
+----------------+

最後に呼ばれた関数のフレームが、スタックの一番上に積まれます。


スタックフレームに入るもの

スタックフレームには主に次の情報が入ります。

1. 戻りアドレス

関数が終了した後、どこに戻るかを示すアドレスです。

main → funcA

funcAが終わったら、mainの続きに戻ります。
そのため、戻り先を保存しておく必要があります。


2. 関数の引数

関数に渡された引数もスタックに保存されます。

void func(int a, int b)

この ab がスタックフレームに配置されます。


3. ローカル変数

関数内で宣言した変数です。

void func() {
    int x = 10;
}

この x はスタックフレーム内に保存されます。

関数が終了すると、フレームが破棄されるため
ローカル変数も消えます。


図:スタックフレームのイメージ

+----------------------+
| ローカル変数        |
+----------------------+
| 保存されたレジスタ  |
+----------------------+
| 戻りアドレス        |
+----------------------+
| 関数の引数          |
+----------------------+

このまとまりが1つのスタックフレームです。


再帰が動く理由

スタックフレームがあるおかげで、同じ関数でも複数回呼び出せます。

例:

factorial(3)

呼び出しのイメージ

factorial(3)
factorial(2)
factorial(1)

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

+--------------+
| factorial(1) |
+--------------+
| factorial(2) |
+--------------+
| factorial(3) |
+--------------+

それぞれの呼び出しが別のスタックフレームを持つため、
計算が独立して実行できます。


スタックオーバーフローとの関係

スタックフレームは関数呼び出しごとに増えます。

そのため、

  • 無限再帰
  • 深すぎる再帰

が起きると、スタックがあふれてしまいます。

これが **スタックオーバーフロー(Stack Overflow)**です。


まとめ

スタックフレームとは、関数呼び出し1回分のデータを保存する領域です。

スタックフレームには次の情報が含まれます。

  • 戻りアドレス
  • 引数
  • ローカル変数
  • 保存されたレジスタ

関数呼び出しのたびにスタックに積まれ、
関数終了時に破棄されます。

この仕組みを理解すると、C言語の関数呼び出しや
スタックの動作がより明確になります。

この記事が参考になった方へ

メモリ領域については他の記事でも解説しています。

メモリ領域解説シリーズの全体像はこちら

スタック領域の基本はこちらの記事で解説しています。

技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。

小さなご相談からでもお気軽にご連絡ください。

お問い合わせはこちら

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする


目次