最初に述べたように、関数を作ったときに、積極的にコンパイラにその関数の
型や引数を教えてやれば、コンパイラはもし間違った関数の呼び出しをしたときに
ちゃんとその旨を知らせてくれる。
このようにコンパイラに関数の仕様を知らせるために、関数の仕様を書く事を
関数の宣言という。関数の宣言は、ファイルの先頭、#include
文の後に
書いておくと良い。
関数の宣言は以下の書式で行う。
[関数の型] 関数名( 引数の型 [,...]); |
例 test1(); char itoc(int); float rmap1(int); float test(int, char); char * string(); |
勿論、関数の型(返り値の型)を省略すると整数型と解釈される。
特に、宣言は文なので、最後にセミコロン ;
をつけることを忘れないように
しなければならない。(この点で、関数の定義とは違う点に注意しよう。)
また、引数の型のみを記述しても良いが、引数を次のように書いても良い。分かり やすさから言えば、引数の変数も書いておく方が良いだろう。但し、その引数の変数名 は、完全なダミーで、まったく意味を持たない。
例 test1(); char itoc(int num); float rmap1(int a); float test(int i, char c); char * string(); |
さてここで、関数の宣言がない場合の事を考えてみよう。関数の宣言がなく、 関数が使用される以前に関数が定義されている場合は、何の問題もない。 つまり、関数の定義でもって、関数の宣言となる。実は、以前の章で、我々が関数の 宣言なしで関数を定義しても大丈夫だったのは、このためである。では、逆に、 関数が宣言、定義される前に、関数が使用されたらどうなるのであろうか。 コンパイラは、その関数がどこか別のところ(例えば、標準ライブラリ)にある と考えるが、宣言はないので、整数型の関数だと決めつけてしまう。 すると、後からそれとは違う関数の宣言や定義を行っても、それは、既に あると考えられているので、2重に宣言・定義されていると見なされ、エラーに なる。また、整数型の関数ならば宣言せずに定義の前に引用しても良いが、 一般にはそうしたものはバグであることが多いので、コンパイラーは一応 警告(Warning) を出すので注意しよう。
コンパイルエラーになる例 #include <stdio.h> main() { test1(2,3); } char test1(int i, int j){ printf("%d %d", i, j); return '!'; } |
具体的なエラーメッセージは、今の場合、7行目の関数の定義がおかしいと思われて、
"test.c", line 7: identifier redeclared: test1というエラーが出る。このエラーの意味は、test1 が2重に宣言されているという意味 である。
このエラーを回避するには、次のように関数を宣言しておくか、
コンパイルエラーにならない例1 #include <stdio.h> char test1(int i, int j); /* 関数宣言 */ main() { test1(2,3); } char test1(int i, int j){ printf("%d %d", i, j); } |
又は、次の例のように、関数が使用される前に、定義すれば良い。
コンパイルエラーにならない例2 #include <stdio.h> char test1(int i, int j){ printf("%d %d", i, j); } main() { test1(2,3); } |
勿論、望ましいのは、例1の関数宣言を用いるほうである。