私はCに少し慣れていません(以前のJava、C#、およびいくつかのC ++の経験があります)。Cでは、関数プロトタイプを宣言する必要がありますか、それともコードはそれなしでコンパイルできますか?そうすることは良いプログラミングの習慣ですか?それとも、コンパイラに依存しているだけですか?(私はUbuntu 9.10を実行しており、Code :: BlocksIDEでGNUCコンパイラ(gcc)を使用しています)
10 に答える
「古い」C(C89 / 90を含む)でも新しいC(C99)でも、Cで関数のプロトタイプを宣言する必要はありません。ただし、関数宣言に関しては、C89/90とC99の間に大きな違いがあります。
C89 / 90では、関数を宣言する必要はまったくありませんでした。呼び出しの時点で関数が宣言されていない場合、コンパイラは呼び出しで渡された引数の型から暗黙的に宣言を「推測」(推論)し、戻り型がであると想定しint
ます。
例えば
int main() {
int i = foo(5);
/* No declaration for `foo`, no prototype for `foo`.
Will work in C89/90. Assumes `int foo(int)` */
return 0;
}
int foo(int i) {
return i;
}
C99では、呼び出すすべての関数は、呼び出しのポイントの前に宣言する必要があります。ただし、プロトタイプで具体的に宣言する必要はありません。非プロトタイプ宣言も同様に機能します。これは、C99では「暗黙のint
」ルールが機能しなくなったことを意味します(この場合、推論された関数の戻り型の場合)が、関数がプロトタイプなしで宣言されている場合は、引数の型からパラメーターの型を推測できます。
foo
前の例は、呼び出しの時点で宣言されていないため、C99ではコンパイルされません。ただし、非プロトタイプ宣言を追加することはできます
int foo(); /* Declares `foo`, but still no prototype */
int main() {
int i = foo(5);
/* No prototype for `foo`, although return type is known.
Will work in C99. Assumes `int foo(int)` */
return 0;
}
...
有効なC99コードになります。
それでも、関数を呼び出す前に、関数のプロトタイプを宣言することをお勧めします。
追記:関数プロトタイプを宣言する必要はないことを上で述べました。実際、一部の機能ではそれが要件です。たとえば、Cで可変個引数関数を適切に呼び出すには、呼び出しのポイントの前にプロトタイプを使用して関数を宣言する必要があります。それ以外の場合、動作は未定義です。これは、C89/90とC99の両方に適用されます。printf
ANSI C(C89またはC90を意味する)では、関数プロトタイプを宣言する必要はありません。ただし、それらを使用することをお勧めします。標準でそれらを使用できないようにする唯一の理由は、非常に古いコードとの下位互換性のためです。
プロトタイプがなく、関数を呼び出すと、コンパイラーは、関数に渡したパラメーターからプロトタイプを推測します。後で同じコンパイル単位で関数を宣言する場合、関数のシグネチャがコンパイラが推測したものと異なると、コンパイルエラーが発生します。
さらに悪いことに、関数が別のコンパイルユニットにある場合、プロトタイプがないとチェックする方法がないため、コンパイルエラーを取得する方法はありません。その場合、コンパイラーがそれを間違えた場合、関数呼び出しが関数が期待するものとは異なるタイプをスタックにプッシュすると、未定義の動作が発生する可能性があります。
慣例では、関数を含むソースファイルと同じ名前のヘッダーファイルでプロトタイプを常に宣言します。
C99またはC11では、標準Cでは、関数を呼び出す前にスコープ内で関数宣言が必要です。多くのコンパイラは、強制しない限り、実際にはこの制限を強制しません。
関数が使用前に定義されている場合は、必須ではありません。
必須ではありませんが、プロトタイプを使用しないことはお勧めできません。
プロトタイプを使用すると、コンパイラーは、(正しい数とタイプのパラメーターを使用して)関数を正しく呼び出していることを確認できます。
プロトタイプがなければ、これが可能です。
// file1.c
void doit(double d)
{
....
}
int sum(int a, int b, int c)
{
return a + b + c;
}
この:
// file2.c
// In C, this is just a declaration and not a prototype
void doit();
int sum();
int main(int argc, char *argv[])
{
char idea[] = "use prototypes!";
// without the prototype, the compiler will pass a char *
// to a function that expects a double
doit(idea);
// and here without a prototype the compiler allows you to
// call a function that is expecting three argument with just
// one argument (in the calling function, args b and c will be
// random junk)
return sum(argc);
}
Cでは、関数プロトタイプを宣言せずに関数定義を使用しても問題はなく、関数の戻り型が「整数」の場合、プログラムはコンパイルして出力を生成します。他のすべての条件では、コンパイラエラーが表示されます。その理由は、関数を呼び出して関数プロトタイプを宣言しない場合、コンパイラは整数を返すプロトタイプを生成し、同様の関数定義を検索するためです。関数プロトタイプが一致する場合は、正常にコンパイルされます。戻り型が整数でない場合、関数プロトタイプは一致せず、エラーが生成されます。したがって、ヘッダーファイルで関数プロトタイプを宣言することをお勧めします。
Cでは、以前に宣言されていなくても関数を呼び出すことができますが、間違った引数を使用した場合にコンパイラが節約できるように、使用する前にすべての関数のプロトタイプを宣言することを強くお勧めします。
関数宣言はヘッダーファイル(Xh)に、定義はソースファイル(Xc)に配置する必要があります。次に、他のファイルが#include "X.h"
関数を呼び出すことができます。
C99
標準によれば、関数プロトタイプは必須ではありません。
呼び出し元のコードをコンパイルするための関数を宣言する必要は絶対にありません。ただし、注意点があります。宣言されていない関数は戻るint
と想定され、コンパイラは最初に関数が宣言されていないことについて警告を発行し、次に戻りタイプとパラメータタイプの不一致について警告を発行します。
プロトタイプで関数を適切に宣言することがはるかに優れた方法であることは明らかです。
「オプション」メニューを選択してから、「コンパイラ」|「コンパイラ」を選択します。C++オプション'。ポップアップ表示されるダイアログボックスで、[C++コンパイラを使用する]オプションで[常にCPP]を選択します。もう一度[オプション]メニューを選択し、[環境]、[環境]の順に選択します。編集者'。デフォルトの拡張子が「CPP」ではなく「C」であることを確認してください。