C89、C90、またはC99のすべての機能にプロトタイプが必要ですか?
質問
真に標準に準拠するためには、Cのすべての関数(mainを除く)がプロトタイプを持っている必要があります(同じ翻訳単位での定義後にのみ使用される場合でも)
解決
「真に標準に準拠している」という意味によって異なります。ただし、簡単な答えは「使用する前にすべての関数のスコープがプロトタイプであることを確認することをお勧めします」
です。より限定的な回答では、関数が変数引数(特に printf()
ファミリの関数)を受け入れる場合、厳密に標準に準拠するためにプロトタイプがスコープ内になければならないことに注意しています。これは、C89(ANSIから)およびC90(ISOから。セクション番号を除いてC89と同じ)にも当てはまります。ただし、「varargs」関数以外では、 int
を返す関数を宣言する必要はありません。また、 int
以外の何かを返す関数は、戻り値の型ですが、引数リストのプロトタイプは必要ありません。
ただし、プロトタイプがない場合に関数が「通常のプロモーション」の対象となる引数を取る場合(たとえば、 char
または short
-どちらも int
に変換されます;より深刻なのは、おそらく double
ではなく float
を受け取る関数です)プロトタイプが必要です。古いCコードを標準準拠のコンパイラでコンパイルできるようにするため、標準ではこれが緩いものでした。古いコードは、関数が使用前に宣言されることを保証することを心配するように書かれていませんでした-定義により、古いコードは標準が存在するまでCで利用できなかったため、プロトタイプを使用しませんでした。
C99は、「暗黙的なint」を許可しません。つまり、「 static a;
」(デフォルトでは int
)のような奇妙なケースと、暗黙の関数宣言の両方を意味します。これらは、ISO / IEC 9899:1999の序文で(約50のその他の主要な変更とともに)言及されています。
この標準を以前のバージョンと比較します:
- 暗黙的な
int
を削除します …- 暗黙的な関数宣言を削除
ISO / IEC 9899:1990では、§ 6.3.2.2 関数呼び出しの説明:
関数呼び出しで括弧で囲まれた引数リストの前にある式が 識別子のみであり、この識別子の宣言が表示されない場合、その識別子は暗黙的に 関数呼び出しを含む最も内側のブロックで、あたかも次のように宣言されます:
extern int identifier();
登場。 38
38 つまり、ブロックスコープを持つ識別子は、型関数を持たない外部リンケージを持つように宣言されています パラメータ情報と
int
を返します。実際には、タイプ“ functionを持つと定義されていない場合int
を返す、”動作は未定義です。
この段落は1999年の標準にはありません。 C99では static a;
を許可し、C99ではそれを許可しない( static int a;
を必要とする)という言い回しの変更を(まだ)追跡していません。
関数が静的である場合、使用する前に定義することができ、宣言を前に付ける必要はありません。 GCCは、非静的関数が宣言の前に定義されていない場合( -Wmissing-prototypes
)にウィッターを説得できます。
他のヒント
A プロトタイプは、関数のパラメーターの型を指定する関数宣言です。
ANSI C以前(Kernighan& Ritchieの「The C Programming Language」の1978年初版で記述された言語)にはプロトタイプがありませんでした。関数宣言でパラメーターの数またはタイプを記述することはできませんでした。引数の正しい数とタイプを渡すのは呼び出し側の責任でした。
ANSI Cでは、パラメーターの型を指定する宣言「プロトタイプ」が導入されました(初期のC ++から借用された機能)。
C89 / C90(ANSIおよびISO標準は同じ言語を記述しています)の時点では、目に見える宣言なしで関数を呼び出すことは合法です。暗黙の宣言が提供されます。暗黙の宣言が実際の定義と矛盾する場合(たとえば、 sqrt(" foo")
を呼び出す場合、動作は未定義です。この暗黙の宣言もプロトタイプでない宣言も、可変個性関数なので、可変個性関数( printf
や scanf
など)の呼び出しには、目に見えるプロトタイプが必要です。
C99は暗黙の宣言を削除しました。目に見える宣言のない関数の呼び出しは制約違反であり、コンパイラの診断が必要です。しかし、その宣言はまだプロトタイプである必要はありません。パラメータタイプを指定しない古いスタイルの宣言を使用できます。
C11はこの領域に大きな変更を加えませんでした。
したがって、2011 ISO C標準の時点でも、古いスタイルの関数の宣言と定義(1989年以降「廃止」された)は、コードの適合において引き続き許可されています。
スタイルの問題として、1989年に遡るCのすべてのバージョンでは、すべての関数にプロトタイプを使用しない理由はほとんどありません。古いスタイルの宣言と定義は、古いコードを壊さないようにするためだけに保持されます。
いいえ、関数は必ずしもプロトタイプを必要としません。唯一の要件は、関数を「宣言」することです。使用する前に。関数を宣言する方法は2つあります。プロトタイプを記述する方法、または関数自体を記述する方法("定義と呼ばれます)。定義は常に宣言ですが、すべての宣言が定義ではありません。
はい、すべての関数にはプロトタイプが必要ですが、そのプロトタイプは別の宣言で、または関数の定義の一部として表示されます。 C89以降で記述された関数定義には当然プロトタイプがありますが、古典的なK& Rスタイルで記述した場合、次のようになります。
main (argc, argv)
int argc;
char **argv;
{
...
}
関数定義にはプロトタイプがありません。 ANSI C(C89)スタイルを記述する場合、次のようになります。
main (int argc, char **argv) { ... }
関数定義にはプロトタイプがあります。
新しい関数を書くときのヒントは、mainを下にして上下逆に書くことです。そのため、関数の引数や戻り値の型を変えたときに、プロトタイプを修正する必要がありません。プロトタイプを絶えず修正し、期限切れのコンパイラのすべての警告に対処するのは非常に面倒です。
関数がスムーズに機能するようになったら、コードを適切な名前のモジュールに移動し、同じ名前の.hファイルにプロトタイプを配置します。それは深刻な時間を節約します。 5年で見つけた最大の生産性向上ツール。
(ANSI C89 / ISO C90で)私の知る限り、いいえ。私はC99について確信がありません。しかし、私は同じことを期待しています。
個人的な注意:関数プロトタイプは、次の場合にのみ記述します...
- (A()がB()を呼び出す場合および B()がA()を呼び出す場合)、または
- 関数をエクスポートしています。それ以外の場合は、余計に感じます。