第2章27 自作関数を作りプロトタイプ宣言を利用する@イチからゲーム作りで覚えるC言語

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
2章28 自作関数で引数とプロトタイプ宣言を使う
NEXT : 2章28 自作関数で引数とプロトタイプ宣言を使う
2章26 自作の関数を作ってみる : PREV

この記事でやること

前回は、プロジェクト「0210_myfunc」を作り、関数を自作する方法についてお話しま

今回は、新しくプロジェクト「0220_func_prototype」を作り、関数のプロトタイプ宣言についてお話します。関数が大量になったときなど、関数のプロトタイプ宣言をすることの利点を、お話していきます。

この記事はゆる~くC言語でコンソールゲームを作りながらプログラミングを学ぶための連載記事です。シリーズものですので記事の一覧はこちらを参照してくださいね。

関数のプロトタイプ宣言を行う利用するプログラム

自作の関数を作りとき、関数のプロトタイプ宣言を行った時のソースコードを書いて動かしてみましょう。プログラムの結果は前回と同じとなるはずです。
プロジェクト「0220_func_prototype」を新しく作成し、ソースコード「MyFuncPrototype.c」を作成してみてください。

#include <stdio.h>
#include <stdlib.h>
// 関数のプロトタイプ宣言
int kinokoHiroi();

int main() {
 for (int i = 0; i < 4; i++) {
   int toretaKinoko = kinokoHiroi();
   printf("ぷらんくは %d 本のキノコを採取しました。\n", toretaKinoko);
 }
}

int kinokoHiroi() {
 int kinoko = rand() % 3 + 1;
 return kinoko;
}

このコードを実行してみるとこんな結果になったかと思います。

ぷらんくは 3 本のキノコを採取しました。
ぷらんくは 3 本のキノコを採取しました。
ぷらんくは 2 本のキノコを採取しました。
ぷらんくは 2 本のキノコを採取しました。

同じように、ぷらんくはランダムに4回、キノコを採取しました。

プロトタイプ宣言とは

プロトタイプ(prototype)とは日本語で「原型」とか「建築でいうところの最初の模型」といった意味があります。

ソースコードの最初のほうで、あらかじめこんな名前・形式の関数を使いますよ、と宣言しておくことをプロトタイプ宣言と呼びます。どんなことに役に立っているでしょうか。

前回のソースコードでも関数を作りましたが、そこではプロトタイプ宣言は出てきていませんでした。これはビルドするときの流れに関係があります。

Visual Studio 等でコンパイルするとき、ソースコードをCPUが読み込みできる機械語に変換するとき、C言語のソースコードを上から下に向けて読み込んでいきます。順番に上から下にソースコードを読むとき、関数の宣言と定義を読み込む前に、関数の呼び出しが行われてしまうと、「そんな関数みつからんし・・。上から見ていったけど宣言・定義も書いてなかったし・・。」ということでエラーとなってしまいます。

関数宣言なしで関数利用とときのVisualStudio警告

関数宣言なしで関数利用とときのVisualStudio警告

試しに、今回のコードで 4 行目のプロトタイプ宣言をコメントアウトすると、上のような警告メッセージが表示されます。

Visual Studio では一応、main関数の後で書いてある kinokoHiroi 関数を呼びだせばいいのでは・・?と紐づけして、実行できる状態にはしてくれます。

つまり、自作関数を呼び出すような処理の前に、関数の宣言と定義が書いてあれば問題ありません。

関数の宣言&定義を使用する前に書く

関数の宣言&定義を使用する前に書く

ですが、これも関数が多くなってくると問題があります。関数から関数を呼び出すこともありますし、どの関数を最初に宣言、定義してあげればよいのか複雑になってきます。
例えば、funcA の中から funcC を呼びだしているとき、funcC を先に書かないといけないですね。funcC からさらに funcB を呼び出しているときはどうでしょうか。
funcB → funcC → funcA → main 関数の順番で書いていかないといけません。実際に大きなプログラムを書くときは、関数の呼び出しの順番はさらに複雑になることもあります。

関数定義の順番を考える

関数定義の順番を考える

プロトタイプ宣言をすることで、このような順番を考えて関数の宣言&定義をしなくても良くなります。
ソースコードの最初に、
「このソースコードの中ではとりあえず、こういう名前と引数を持つ関数が後ろの方で具体的に書いてある(定義してある)予定なので、中身までは書いていないけど呼び出しできるハズ」とコンパイラに教えてあげることができます。
プロトタイプ宣言の書き方は下のようになります。

戻り値の型  関数名 ( 引数1の型 引数1の変数名, 引数2の型 引数2の変数名, … 略 … );

引数の変数名は省略して、下のように書くこともできます。どちらでも問題なく同じ動きをしますが、なんとなく直感的にどのような値を入れたらよいのかわかるように、変数名は書いておくことをお勧めします。

※VisualStudio などの IDE による関数名の参照機能(IntelliSense)などで、どのような関数なのか情報を表示するときに役に立つことがあるからです。

戻り値の型  関数名 ( 引数1の型, 引数2の型, … 略 … );

前回書いた関数の宣言&定義のうち、{…}を省略した形になっており、これで、こういった関数が用意されていると宣言できます。

ソースコードを追ってみよう

今回のソースコードを簡単に上から見てみましょう。

キノコ拾い関数のプロトタイプ宣言

// 関数のプロトタイプ宣言
int kinokoHiroi();

ソースコードの include 文の直後に、関数のプロトタイプ宣言が行われています。
「int kinokoHiroi();」という形式の関数がこのソースコードの中のどこかで定義されていることを示しており、「今後 kinokoHiroi() という関数の処理(定義)がまだ読み込まれていないときでも、ちゃんと kinokoHiroi() という処理はどっかに書いてあるので、エラーにしないでね!」ということをコンパイルに伝えてあげています。

main関数からの キノコ拾い関数の呼び出し

その後6行目から main 関数の定義に入ります。

int main() {
 for (int i = 0; i < 4; i++) {
  int toretaKinoko = kinokoHiroi();
  printf("ぷらんくは %d 本のキノコを採取しました。\n", toretaKinoko);
 }
}

main関数の中で 8 行目に kinokoHiroi() 関数を呼び出しするように書いてありますが、もしプロトタイプ宣言が書いていなければ、「そんな関数ないです」というエラーや警告メッセージが出て、正しくビルドが失敗する可能性があります。

キノコ拾い関数の実態の定義

13行目からプロトタイプ宣言していた kinokoHiroi 関数の定義をしています。

int kinokoHiroi() {
 int kinoko = rand() % 3 + 1;
 return kinoko;
}

これを書かないと、main関数から kinokoHiroi 関数を呼び出ししようとしたとき、「やっぱそんな関数ないじゃん」ということでエラーになってしまいます。

あとがき

プロトタイプ宣言の基本についてお話しました。今後ソースコードのサイズが大きくなっていき、たくさんの関数を扱うようになったときは、地味ながら必須の知識になるかと思います。

今回はここまで。おつかれさまでした。

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
2章28 自作関数で引数とプロトタイプ宣言を使う
NEXT : 2章28 自作関数で引数とプロトタイプ宣言を使う
2章26 自作の関数を作ってみる : PREV

非常に参考になったサイトさまや、参考文献など

ページの更新履歴

更新日 更新内容
更新なし