プロトタイプ宣言は関数の事前申告
リスト1に、もういちど前回のプログラム(関数を使ったスプーンの音待ち)を示します。実際にビルドして試されましたでしょうか? 中には運良く見慣れぬエラーになってしまった方もいらっしゃるでしょう。エラーの出なかった方は、リスト2のようにmain関数を一番最初に記述するように書き換えてみて、再度ビルドしてみてください。
void AllLedOff( ) { P12.3 = 0 ; P4.5 = 0 ; P13.0 = 0 ; P2.3 = 0 ; P2.2 = 0; return; } void WaitSound() { while( P3.0 == 1 ){ ; } return; } void Led_D7( int onoff ) { if ( onoff == 1 ){ P12.3 = 1; } else{ P12.3 = 0; } return; } void main( void ) { AllLedOff(); WaitSound(); Led_D7( 1 ); while(1){ ; } }
void main() { : } void AllLedOff( ) { : } void WaitSound() { : } void Led_D7( int onoff ) { : }
さてこれをビルドすると以下のエラーが表示されます。
main.c(54) : W745 Expected function prototype main.c(55) : W745 Expected function prototype main.c(57) : W745 Expected function prototype main.c(66) : F747 Function prototype mismatch main.c(78) : F747 Function prototype mismatch main.c(87) : F747 Function prototype mismatch
最初の3つのExpected function prototypeは、main関数で他の関数を呼び出している各行について警告が出ています。内容は、「呼び出している関数がプロトタイプ宣言されていないよ」という意味です。あとの3つ、Function prototype mismatchは、AllLedOff()、WaitSound()、Led_D7()の各関数の宣言場所でエラーになっています。内容は「関数のプロトタイプが合っていない」というものです。
さあ、このプロトタイプとは何でしょうか。それは、関数の型の事前申告です。たとえばmain関数では最初にAllLedOff()を呼び出します。このとき、Cコンパイラは初めてこのAllLedOff()に出会います。この関数に引数があるのか、戻り値の型は何なのかわからないままにです。そこでCコンパイラは、文法的に正しいかどうかチェックすることができず、警告を表示してプログラマに知らせてくるのです。と同時に、とりあえず初めて見た関数はint型と仮定して先に進めます。
すると今度は、呼び出される関数の実体と出会います。実体はintなどではなく、void型なので、Cコンパイラはここは明らかに間違っているという判断をして「型が違う」と、今度はエラーを表示しているわけです。
これを解決するには、「関数を使う前に申告しておく」ことを行います。申告の書式は、以下のとおりです。
型 関数名 (引数型, 引数型……) ;
リスト1に登場する3つの関数のプロトタイプ宣言は、以下のようになります。
void AllLedOff( void ); void WaitSound( void ); void Led_D7( int onoff );
引数のないものは、戻り値がない場合と同様にvoidという言葉で引数がないことを明示します。また、引数のあるものは、型だけでなく変数名も書いてもOKです。ですからLed_D7()のプロトタイプ宣言は、以下のどちらでもOKです。
void Led_D7( int onoff ); void Led_D7( int );
この宣言を、関数を使う(呼び出す)前、つまりmain()関数の前に記述して、ビルドしてみてください。今度はエラーなくビルドできたはずです。