プロトタイプ宣言
main を下に置くと壊れる
ここまで、関数の定義は必ず main より上に書いてきました。しかし読み手の立場になると、プログラムの入口である main が一番下にあるのは読みにくいものです。main を先頭に置きたくなります。やってみましょう。
#include <stdio.h>
int main(void) {
printf("合計は%d点です\n", total_of(80, 90, 85));
return 0;
}
int total_of(int a, int b, int c) {
return a + b + c;
}これをコンパイルすると、実行ファイルはできずにエラーが出ます。
error: call to undeclared function 'total_of'宣言されていない関数 total_of を呼んでいる、という意味です。関数はちゃんと下に書いてあるのに、なぜでしょうか。
コンパイラは上から1回だけ読む
理由は、C のコンパイラがソースを 上から順に1回だけ 読んでいくからです。4行目の total_of(...) に来た時点では、コンパイラはまだ 8 行目を見ていません。そんな名前は聞いたことがない、という状態です。
しかもコンパイラは、名前を知らないと呼び出しコードを作れません。引数として int を3つ渡すのか double を渡すのか、返ってくるのは int なのか double なのかが分からないと、機械語に落とせないためです。必要なのは処理の中身ではなく、名前と型の情報 だけです。
プロトタイプ宣言
そこで、中身は後回しにして型の情報だけを先に教えます。これが プロトタイプ宣言 です。
int total_of(int a, int b, int c);関数定義の1行目から波カッコを取り除き、代わりにセミコロンを付けた形です。中身がないので、これだけでは何も実行されません。「こういう名前で、こういう型の関数が、このソースのどこかにあります」とコンパイラに約束する行です。
これを main より上に置けば、main を先頭に書けます。
#include <stdio.h>
int total_of(int a, int b, int c);
double average_of(int a, int b, int c);
int main(void) {
printf("合計は%d点です\n", total_of(80, 90, 85));
return 0;
}
int total_of(int a, int b, int c) {
return a + b + c;
}
double average_of(int a, int b, int c) {
return (a + b + c) / 3.0;
}宣言に書く引数の名前は省略でき、int total_of(int, int, int); でも通ります。ただ、読み手には名前があったほうが親切なので、定義と同じ名前を書いておくのが普通です。
セミコロンの付け忘れ
よくある事故は、宣言の末尾のセミコロンを忘れることです。すると次の行と地続きになって、コンパイラは関数定義が始まったと勘違いします。エラーの内容が原因の行とかけ離れるので、宣言をまとめて書いた直後にエラーが出たら、まずセミコロンを疑ってください。
ちなみに #include <stdio.h> の正体も、printf や scanf のプロトタイプ宣言が並んだファイルです。第1章で書いていた1行は、この仕組みそのものだったわけです。
要件
- total_of と average_of のプロトタイプ宣言を main より上に書く
- total_of と average_of の定義は main より下に書く
- scanf で3つの整数を読み込む
- 1行目に 合計は255点です の形で表示する
- 2行目に 平均は85.0点です の形で小数第1位まで表示する
入出力例
main("80 90 85") → "合計は255点です
平均は85.0点です"
main(60, 55, 71) → "合計は186点です
平均は62.0点です"