ANSI C 関数宣言に関して、これは古い K&R スタイルからどのように改善されていますか? 私はそれらの違いを知っています.古いスタイルを使用するとどのような問題が発生する可能性があるのか 、新しいスタイルがどのように改善されるのかを知りたいだけです.
2 に答える
特に、古いスタイルの関数宣言では、コンパイル時の呼び出しのチェックはできません。
例えば:
int func(x, y)
char *x;
double y;
{
/* ... */
}
..。
func(10, 20);
コンパイラーは呼び出しを見ると、関数のパラメーターのタイプを知らないfunc
ため、エラーを診断できません。
対照的に:
int better_func(char *x, double y) {
/* ... */
}
..。
better_func(10, 20);
コンパイラのエラーメッセージ(または少なくとも警告)が表示されます。
もう1つの改善点:プロトタイプにより、タイプのパラメーターと、 (3つのタイプと2つのタイプ)float
よりも狭い整数タイプのパラメーターを持つ関数を使用できるようになります。プロトタイプがない場合は、にプロモートされ、狭整数型はまたはにプロモートされます。プロトタイプでは、引数は(のように関数が可変個引数である場合を除き、その場合、古い規則が可変個引数に適用されます)として渡されます。int
char
short
float
double
int
unsigned int
float
float
printf
C Rationaleドキュメントでは、これについてセクション6.7.5.3で説明していますが、おそらく私が持っているよりも優れています。
関数プロトタイプメカニズムは、C言語への最も有用な追加機能の1つです。もちろん、この機能は、過去25年間のAlgolから派生した言語の多くで前例があります。標準で採用されている特定の形式は、主にC++に基づいています。
関数プロトタイプは、強力な変換時エラー検出機能を提供します。プロトタイプを使用しない従来のCプラクティスでは、トランスレータが別のソースファイルで宣言された関数の呼び出しでエラー(引数の数またはタイプが間違っている)を検出することは非常に困難です。このようなエラーの検出は、実行時または補助ソフトウェアツールの使用によって発生しました。
関数プロトタイプのスコープにない関数呼び出しでは、整数引数に整数昇格が適用され、float引数がdouble に拡張されます。このような呼び出しでは、変換されていないcharまたはfloat引数を渡すことはできません。関数プロトタイプを使用すると、プログラマーは関数の引数の型変換を明示的に制御できるため、実装によって、引数のデフォルトの拡張ルールが不適切で非効率になることがよくあります。
もっとあります。読んでください。
K&R での非定義関数宣言は次のようになります。
int foo();
不特定数の引数を受け入れる関数を導入します。このような宣言スタイルの問題は明らかです。パラメーターの数もその型も指定していません。呼び出しの時点で、コンパイラが引数の数またはその型に関して呼び出しの正確性をチェックする方法はありません。引数の型が予期されるパラメーターの型と一致しない場合、コンパイラが引数の型変換を実行したり、エラー メッセージを発行したりする方法はありません。
K&Rで関数定義の一部として使用される関数宣言は、次のようになります。
int foo(a, b)
int a;
char b;
{ ...
パラメータの数を指定しますが、それらのタイプは指定しません。さらに、この宣言によってパラメーターの数が公開されているように見えますが、形式的には宣言foo
と同じ方法で宣言int foo();
されfoo(1, 2, 3, 4, 5)
ています。
新しいスタイル、つまりプロトタイプを使用した宣言の方が明らかな理由で優れています。パラメーターの数と型の両方が公開されます。これにより、コンパイラは呼び出しの有効性を (パラメーターの数と型に関して) チェックするように強制されます。また、コンパイラは、引数の型からパラメーターの型への暗黙的な型変換を実行できます。
プロトタイプ宣言によって提供されるその他のあまり明白でない利点があります。関数パラメーターの数と型は、呼び出し元と関数自体の両方に正確に知られているため、呼び出しの時点で、関数定義を見なくても引数を渡す最も効率的な方法 (呼び出し規則) を選択できます。その情報がなければ、K&R の実装は、すべての関数に対して、あらかじめ決められた単一の「フリーサイズ」の呼び出し規則に従うことを余儀なくされていました。