まず,プログラムの冒頭で,変数と同様に,
int f( int x );
として,プログラムで用いられる関数を宣言する.C++では関数の宣言(プ ロトタイプ宣言)は必須で,無いとコンパイルエラーとなるが,Cでは関数 を呼び出す箇所の前に関数のインプリメンテーション(実装=プロトタイプ の反対で,中身のあるもの)があればコンパイルエラーとならない.例えば,
int f(void){
/* 中身は,省略 */
}
int main(void) {
f();
return 0;
}
は,プロトタイプ宣言が無いが,main()関数の中でf()が呼び出されるよ り前に,関数f()のインプリメンテーションがあるのでエラーとはならない.
このmain()関数とf()関数の順番を逆にして,プロトタイプ宣言を書か ないと警告が出る.関数の戻り値はデフォルトでint型とみなされるのでコ ンパイラーによっては警告がでるだけでコンパイルができてしまう場合もあ る.すなわち,関数はその関数が呼び出される以前にプロトタイプ宣言があ るか,または実装がされているかする必要がある.プロトタイプ宣言の最後 にはセミコロンをつけなければならない.
関数の宣言方法は,
戻り値の型 関数名 ( 関数に渡す引数の型 引数名, ... );
とする.戻り値の型とは例えば
3∗x+ 2
を計算した結果を,どのような型に格納するかを定める.ここでは,結果が 整数と仮定してもよいのでint型になっている.
関数名は,自分で付けたい名前を決めればよい.
ちなみに,古い関数宣言と実装というのが存在する.旧式の関数宣言では int f( int x );
とするかわりに,
int f( int );
のように変数名を書かずに型だけをプロトタイプで宣言する.古い実装は,
int f ( int x ) {
int ret;
ret = 3 * x + 2;
return ret;
}
と書くかわりに int f ( x )
int x;
{
int ret;
ret = 3 * x + 2;
return ret;
}
と書く.つまり,先に変数の名前だけを書き,そのあとで変数の型と名前を 書きセミコロンを書くような書式になる.古い書式で書かれた実装はコンパ イラによっては警告 warninig を出すものがある.ここで紹介した古い宣言 や書式はANSIのCの規格にも,時代遅れであると書かれている.
最後に,関数に渡す引数の型と引数名で,上の例で言えば,関数f()には,
xという変数が必要になる.この変数は,int型で宣言してある.小数点の 値を求めたいときや,y, z などの変数も必要になれば,関数f()は,
float f( float x, float y, float z );
とカンマで区切って宣言する.以上が関数のプロトタイプが宣言である.
関数f()の実装は int f ( int x ) {
int ret;
ret = 3 * x + 2;
return ret;
}
のように最初に,関数の宣言と同じものを書き( ただしセミコロンを除く),
main()と同様に,{と}で囲んだ部分が関数の本体となる.return文の末 尾に,呼び出し先に返す値を書く.このときreturn 文の末尾の型と関数の プロトタイプで宣言した戻り値の型が一致していなければならない.
演習問題 1から100までの全ての素数を表示するプログラムを書け
13.3 #include について
今まで使ってきた main() も printf() も strcpy()も全て関数である.
printf()や strcpy()がプロトタイプ宣言や実装が無いのに使えるのは
#include < ... >
の拡張子が.hで終るファイルに書かれている..hで終るファイルをヘッダ ファイルと言う.gcc をインストールしたディレクトリに/include という ディレクトリがある.このディレクトリこstdio.hという名前のファイルが ある.ヘッダファイルはテキストファイルであるから,エディタなどで見て みることができる.stdio.hにはprintf()のプロトタイプ宣言がなされて いる.
コンパイル時にプリプロセッサとよばれるプログラムが起動され,この
#includeで指定されたファイルが展開される.これにより,printf()など
のプロトタイプ宣言が要らなくなる.
printf()などの実装はgccのインストールされたディレクトリの/libディ レクトリの中の拡張子.aのファイルや.soファイルに入っている.これら のファイルをライブラリと言う.ライブラリファイルはコンパイル済みなの で,エディタで見ることはできない.printf()などは,この内のlibc.aに 入っている.gcc のコンパイラはこのlibc.a をデフォルトで組み込むよう になっている. 一方,libm.aは初期設定では組み込まれていないので,コン パイル時に明示的に指定してやる必要がある.いままでsqrt()などを使う 場合は,
gcc hoge.c -lm
として明示的にライブラリを指定する理由がこれである.
最後にsqrt()は戻り値を左辺に代入することができたが,実はprintf()
も戻り値がある.printf()の戻り値の型は intであり書き込まれた文字数 が返ってくる.今まで行なってきたprint()はその戻り値を利用していない だけの話なのである.
値を返さない関数を作るには戻り値の型をvoid にする.
void NonReturnFunction();