C: プロトタイプ宣言を忘れると何が起きるか

C 言語でソースを書いて、ビルドして実行して、うまくいった。
……が、ここで、プロトタイプ宣言なしで後方の関数を呼び出していたことに気づいた。あれ? こういう場合ってエラーになるんじゃないんだっけ?

元ラッパー「yo!」

void quark()
{
	if (roots("dogeza") != 0)
	{
		exit(1);
	}
}

int roots(char *s)
{
	//...
}

コンパイルしても、エラーは出ない。実行しても問題なく動く。僕が今回使っている環境では、警告も出なかった。

酸使い「ぼくじゃないよぼくじゃないよ」

原典にあたってないんだけど、いくつかのページを見ると、

  • プロトタイプ宣言のない関数を呼び出していると、コンパイラはとりあえず「引数は呼び出し元に書いてある通り。戻り値は int」という仮定を行う。

ということらしい。京都大学講師の安田豊さんによる、下記の授業用テキストがわかりやすい。

関数プロトタイプ
http://ylb.jp/2007b/proc/prototype/

なので、今回の例でうまくいってたのは

  • たまたま戻り値が int だったから
  • たまたま呼び出し元と実際の宣言で引数の形が同じだったから
  • たまたま呼び出し方を間違えなかったから

ということだ。うまくいかない場合の例が、f_yamaki さんによる下記の blog エントリにある。

take short - プロトタイプ宣言の無い関数2
http://pdragon.blog24.fc2.com/blog-entry-134.html

居酒屋店員「そいつはすげぇや!!」

ちなみに、

  • 同じ C でも、C99 では「プロトタイプ宣言がない場合の動作は未定義」になった。
  • C++ ではプロトタイプ宣言がないとエラー。

だそうだ。
あと、直接関係ないけど、引数がない場合のプロトタイプ宣言を行う場合、

  • C では int foo(void) のように void を書く必要がある。書かないとプロトタイプ宣言ではなく「前方宣言」として扱われてしまう
  • C++ では void を書かなくてもいい

という注意点があるらしい。