関数プロトタイプ宣言と古い形式の関数定義がともに機能するためには、両方が機能的に同じインタフェースを指定しなければいけません。つまり、ISO C の用語を使用する互換形式を持っていなければいけません。
可変引数を持つ関数の場合は、ISO C の省略記号と古い形式の varargs() 関数定義は併用できません。固定数のパラメータを持つ関数の場合、以前の実装で渡したとおりのパラメータの型を指定できます。
K&R C では、各引数は、呼び出された関数に渡される直前に、デフォルトの引数拡張に従って変換されました。このような拡張は、int より狭いすべての整数型が int サイズに拡張され、また、任意の float 引数が double に拡張されるように指定していたため、コンパイラとライブラリの両方を単純化していました。関数プロトタイプはより表現力が高いです。指定したパラメータの型が関数に渡されるものになるためです。
したがって、関数プロトタイプが既存の (古い形式の) 関数定義のために記述されている場合、その関数プロトタイプには、次のいずれかの型のパラメータを一切含めないようにしてください: char、signed char、unsigned char、float、short、signed short、unsigned short。
プロトタイプを書く際には、依然として 2 つの問題があります。typedef 名と、狭い unsigned 型の拡張規則です。
古い形式の関数内のパラメータが typedef 名を使って宣言されている場合 (off_t や ino_t など)、typedef 名がデフォルトの引数拡張によって影響を受ける型を指しているかどうかを確認する必要があります。これら 2 つの場合、off_t は long で、関数プロトタイプで使用できます。ino_t は unsigned short であったため、プロトタイプで使用すると、古い形式の定義とプロトタイプが異なる互換性のないインタフェースを指定するため、コンパイラは診断メッセージを発行します。
unsigned short の代わりに何を使用すべきかを決定するのは複雑な問題です。K&R C と 1990 ANSI/ISO C コンパイラ間の最大の非互換性は、unsigned char と unsigned short を int 値に広げるための拡張規則です。(拡張: 符号なし保存と値の保持を参照してください。)この古い形式のパラメータに対応するパラメータ型は、コンパイル時に使用するコンパイルモードによって異なります。
-Xs と -Xt では unsigned int を使用する
–Xa、– Xc、および -std=anyvalue は int を使用する必要があります
最良の方法は、int または unsigned int のどちらかを指定するように古い形式の定義を変更して、一致する型を関数プロトタイプで使用することです。必要であれば、関数を入力したあとでも、より狭い型の値を局所変数に代入できます。
前処理によって影響を受ける可能性のあるプロトタイプでは、ID の使用に注意を払ってください。次の例を考えてみましょう。
#define status 23 void my_exit(int status); /* Normally, scope begins */ /* and ends with prototype */
関数プロトタイプは、狭い型を持つ古い形式の関数定義と併用できません。
void foo(unsigned char, unsigned short); void foo(i, j) unsigned char i; unsigned short j; {...}
__STDC__ を適切に使用すれば、古いコンパイラと新しいコンパイラの両方で使用できるヘッダーファイルを作成できます。
header.h: struct s { /* . . . */ }; #ifdef __STDC__ void errmsg(int, ...); struct s *f(const char *); int g(void); #else void errmsg(); struct s *f(); int g(); #endif
次の関数はプロトタイプを使用していますが、古いシステムでもコンパイルできます。
struct s * #ifdef __STDC__ f(const char *p) #else f(p) char *p; #endif { /* . . . */ }
次の例は、更新されたソースファイルを示しています (前述の選択肢 3 と同様)。局所関数は古い形式の定義を使用していますが、新しいコンパイラ用にプロトタイプも含まれています。
source.c: #include “header.h” typedef /* . . . */ MyType; #ifdef __STDC__ static void del(MyType *); /* . . . */ static void del(p) MyType *p; { /* . . . */ } /* . . . */