6-2 関数のプロトタイプ宣言

この記事は約5分で読めます。

main関数の後で自作関数を定義する

6-1のサンプルコードでは自作関数はすべてmain関数より前に定義していました。しかし自作関数が増えたり、コードが長くなったりするとmain関数より後に定義したほうが読みやすくなる場合もあります。main関数の後に定義して、コードを書き直します。

#include <stdio.h>
int main(void){
	int ans;
	puts("main関数です。");
	printint(3);
	ans=nijou(5);
	printf("nijou(5)の戻り値:%d\n",ans);
	return 0;
}
void printint(int a){
	printf("print関数です。a=%d\n",a);
}
int nijou(int n){
	int ans;
	puts("nijou関数です。");
	ans=n*n;
	return ans;
}

実行結果

コンパイルエラーにより実行できません
エラー表示(筆者の環境の場合)
警告 5行目 プロトタイプ宣言のない関数 'printint' の呼び出し(関数 main )
警告 6行目 プロトタイプ宣言のない関数 'nijou' の呼び出し(関数 main )
エラー 10行目 'printint' の再宣言で型が一致していない

処理系によってはエラーが発生せず実行できる場合もあります。まず、警告が出ているのはmain関数まで読み込んだ時点でprintint関数とnijou関数がまだ定義されていないからです。筆者のコンパイラの場合、まだ定義されていない関数が呼び出された場合は関数の引数の型は呼び出したときの実際の引数から推測し、関数の返却値は自動的にintとみなされるからです。そのため、実際に読み込んだvoid型のprintint関数の定義と自動でコンパイラがint型とみなしたprintint関数が衝突し、エラーとなっています。これを防ぐために、printint関数とnijou関数がどんな型の関数かを前もって宣言しておく必要があります。それが関数のプロトタイプ宣言です。

プロトタイプ宣言

プロトタイプ宣言の仕方は

返却値の型 関数名(引数);

となります。関数の定義の1行目だけを書いて;をつけるとプロトタイプ宣言になります。プロトタイプ宣言をしてコードを書き直すと次のようになります。

#include <stdio.h>
void printint(int a);
int nijou(int n);
int main(void){
	int ans;
	puts("main関数です。");
	printint(3);
	ans=nijou(5);
	printf("nijou(5)の戻り値:%d\n",ans);
	return 0;
}
void printint(int a){
	printf("print関数です。a=%d\n",a);
}
int nijou(int n){
	int ans;
	puts("nijou関数です。");
	ans=n*n;
	return ans;
}

実行結果

main関数です。
print関数です。a=3
nijou関数です。
nijou(5)の戻り値:25

プロトタイプ宣言によって関数の形をコンパイルに知らせることによって、エラーや警告は発生しなくなりました。ちなみに、プロトタイプ宣言は関数の型と引数の型だけが分かればいいので、引数の名前は書く必要はありません。つまり今回の場合2行目と3行目を

void printint(int);
int nijou(int);

としても実行できます。

#include <stdio.h>の意味

今まで使ってきたprintf関数、scanf関数、puts関数のプロトタイプ宣言はstdio.hというファイルの中に記述されています。stdio.hはStandard Input/Output Headerの略で入出力に関する標準的な関数のプロトタイプ宣言がまとめられているファイルという意味です。標準で用意されている関数のプロトタイプ宣言が書かれたファイルはヘッダファイルと呼ばれています。stdio.hはヘッダーファイルの1つです。#includeはヘッダファイルを読み込むという意味で、#includeを使って読み込むことをインクルードすると言います。そのため標準入出力以外の関数を使う場合は別のヘッダファイルをインクルードする必要があります。

int main(void){
	int in;
	puts("整数を入力してください。");
	scanf("%d",&in);
	printf("in=%d\n",in);
	return 0;
}

実行結果

コンパイラのメッセージ (筆者の環境の場合)
警告 3行目 プロトタイプ宣言のない関数 'puts' の呼び出し(関数 main )
警告 4行目 プロトタイプ宣言のない関数 'scanf' の呼び出し(関数 main )
警告 5行目 プロトタイプ宣言のない関数 'printf' の呼び出し(関数 main )
整数を入力してください。
10
in=10

筆者の環境では警告こそ出たもののコンパイルできました。環境によってはエラーになることもあります。

まとめ

main関数の後に関数を定義する場合はmain関数の前に一度プロトタイプ宣言をする必要がある。

ヘッダファイルはプロトタイプ宣言を集めたファイルである。

コメント

タイトルとURLをコピーしました