宣言とプロトタイプ

提供: Appmethod Topics
移動先: 案内検索

関数:インデックス への移動

Kernighan & Ritchie 形式の宣言においては,関数は呼び出されるときに暗黙のうちに宣言されるか,あるいは明示的には次のように宣言することができます。

<型> func();

type はオプションの戻り型で,デフォルトでは int です。C++ では,この宣言は <type func(void) を意味します。関数は,配列型と関数型を除いてどのような型でも返すことができます。この方法では,コンパイラが,関数呼び出しで使用された型および引数の個数が宣言と一致しているかどうかをチェックできません。

この問題は,次の宣言構文を持つ関数プロトタイプの導入によって改善されました。

<型> func(パラメータ宣言子リスト);

メモ:  IDE 内またはコマンドラインコンパイラでは,次の警告を出すようにできます。「Call to function ' 関数名 ' with no prototype(プロトタイプのない関数の呼び出し)」

宣言子は,関数の各パラメータの型を指定します。コンパイラは,この情報を使用して関数呼び出しが有効かどうかをチェックします。またコンパイラは,引数を適切な型に強制することができます。次のようなコードを考えてみてください。

extern long lmax(long v1, long v2); /* プロトタイプ*/
foo()
{
   int limit = 32;
   char ch = 'A';
   long mval;
   mval = lmax(limit,ch);    /* 関数呼び出し */
}

lmax の関数プロトタイプがあるので,このプログラムは,lmax への呼び出しに備えて limit と ch をスタックに置く前に,標準の代入規則に従ってこれらを long に変換します。関数プロトタイプがないと,limit と ch をそれぞれ整数と文字としてスタックに置くことになりますが,その場合 lmax に渡されるスタックのサイズと内容は,lmax が想定しているものとは一致せず,問題を引き起こしてしまいます。古典的な宣言形式では,パラメータの型と個数のチェックは行えないので,関数プロトタイプを使うことはプログラミングエラーを追跡するためにたいへん役立つわけです。

関数プロトタイプは,コードのドキュメント性を高めるためにも役立ちます。たとえば,関数 strcpy はコピー元の文字列とコピー先の文字列の 2 つのパラメータを持っています。問題は,どちらがどちらかということです。次のような関数プロトタイプを見れば,それがはっきりします。

char *strcpy(char *dest, const char *source);

ヘッダーファイルに関数プロトタイプがある場合は,ヘッダーファイルをプリントアウトすれば,それらの関数を呼び出すプログラムを書くために必要な情報を得ることができます。プロトタイプのパラメータに識別子が含まれている場合,その識別子はパラメータによってエラーが生じたときだけ,エラーメッセージの中で使用されます。それ以外の作用はありません。

次のようにカッコの中に void しか入っていない関数宣言子は,その関数が引数をとらないことを意味します。

func(void);

C++ では,func() も引数を持たない関数を示します。

関数プロトタイプは,通常は一定の個数のパラメータをとるものとして関数を宣言します。可変個のパラメータをとる C の関数(printf など)の関数プロトタイプでは,次のように省略記号(...)を指定します。

f(int *count, long total, ...);

この形式のプロトタイプでは,固定パラメータはコンパイル時にチェックされ,可変パラメータは型チェックなしで渡されます。

メモ:  stdarg.h と varargs.h には,可変個のパラメータをとるユーザー定義の関数で使用できるマクロが含まれています。

以下に,関数宣言子とプロトタイプの例を示します。

int  f();                    /* C では,int を返し,引数情報のない関数.
                             これは K&R の伝統的形式. */
int f();                     /* C++ では,引数をとらない関数 */
int  f(void);                /* 引数をとらず int を返す関数 */
int  p(int,long);            /* 2 つのパラメータ
                             最初は int 型,2 番めは long 型)
                             を受け取る int を返す関数。*/
int  __pascal q(void);       /* int を返すパラメータなしの
                             pascal 型の関数 */
int  printf(char *format,...);   /*int を返し,char 
     の固定パラメータと任意の数の未知の型の追加パラメータを受け取る関数。*/
int  (*fp)(int);             /* int を返し,int 
                             パラメータを要求する関数へのポインタ */