2

本やウェブサイトを見ると、関数宣言/プロトタイプは必須だと書かれていますが、宣言せずにプログラムを実行すると、正しい結果が得られます。

理由を説明できますか?

4

7 に答える 7

7

(関数の定義がそれを呼び出す関数の前にない場合について話しているので、関数定義はプロトタイプに関する情報を提供できません。そうでない場合、関数の宣言は必須ではありません。ただし、関数定義の順序に依存せず、その順序を変更してもエラーが発生しにくいため、依然として良い方法と見なされています。)

呼び出し規約(プラットフォームのABIの一部) は、関数が返し、引数として受け入れる型に基づいて、引数と戻り値のさまざまな場所を定義できるため、関数宣言は重要です。たとえば、(十分な大きさの) 構造体を返す関数の戻り値は通常、スタックに配置されますが、int通常、返す関数は戻り値に CPU レジスタを使用します。関数プロトタイプがない場合、ほとんどのコンパイラは関数が を返すと想定しますがint、これは誤りである可能性があります。次の例を検討してください。

// in a separate implementation file
struct foo {
    long long bar;
    char buf[128];
};

struct foo function()
{
    struct foo f = { 0 };
    return f;
}

// in another file - the implementation is invisible here,
// and in the lack of a prototype, the compiler assumes an integer return value
int x = function();

関数が戻り値をスタックにプッシュするため、スタックが混乱する可能性がありますが、整数の戻り値を想定しているため、代入はそれをポップしません。

于 2012-12-28T09:05:28.447 に答える
3

部分的には、コードが準拠している標準によって異なります。先行標準コンパイラは、プロトタイプをまったくサポートしていなかったため、非常に緩いものでした。C89 標準ではプロトタイプが導入されましたが、既存の膨大なコード本体をコンパイルできるようにする必要がありました。そのため、プロトタイプはオプションでした (ただし、技術的には、printf()可変数の引数をサポートするような関数は除きます。C89 ではプロトタイプは必須でした。ただし、宣言が欠落している場合、コンパイラは通常は文句を言ったり、問題を引き起こしたりしませんでした)。

C99 (および C2011) では、関数を使用する前に各関数のプロトタイプ宣言を表示する必要があります。非静的関数を定義する前に、各非静的関数のプロトタイプ宣言を表示することをお勧めします。その宣言は、関数を使用する他のファイルが含めることができるヘッダーにある必要があります。ヘッダーは「審判」として機能します。これにより、関数を使用するコードに正しい宣言情報が含まれ、関数を定義するコードが他のすべてが使用している宣言と一致することが保証されます。

通常、コンパイラを厳密モードにしない限り、コンパイラはプログラムを受け入れようとします。GCCなどにオプションを追加-std=c99 -pedantic -Wall -Wextraすると、多くの警告が有効になります。これらのオプションの下でコードをきれいにコンパイルする価値があります。

GCC を使用している場合は、警告にさらに多くのオプションを追加して、省略が通知されるようにすることができます。GCC のバージョンに応じて、以下を使用できます。

  • -Wmissing-prototypes(プロトタイプがない場合は警告します)
  • -Wstrict-prototypes( などの非プロトタイプについて警告しますextern int func();)
  • -Wold-style-declaration(「古いスタイル」、K&R、非プロトタイプ宣言について警告します)
  • -Wold-style-definition(「古いスタイル」、K&R、プロトタイプではない定義について警告します)

私は最初の 2 つを何年も使用してきました。すべての GCC 4.x および 3.x シリーズのコンパイラでさえ、それらをサポートしています。後者の 2 つは、昨年かそこらで出会っただけです。GCC 4.7.x はそれらをサポートしていますが、GCC 4.1.x はサポートしていません (4.5.1 はそれらをサポートしています。これは、手元にある 4.1.2 以外の最も古いバージョンです)。

GCC 4.7.x には便利なオプションがあります: gcc --help=warnings. これにより、サポートされているすべての警告のリストが簡単な要約とともに表示されます。

...
-Wmissing-prototypes        Warn about global functions without prototypes
...
-Wold-style-declaration     Warn for obsolescent usage in a declaration
-Wold-style-definition      Warn if an old-style parameter definition is used
...
-Wstrict-prototypes         Warn about unprototyped function declarations
...
于 2012-12-28T09:17:29.237 に答える
2

関数宣言/プロトタイプを使用することは、非常に優れたプラクティス/設計です (必要がない場合)。

多くの場合、選択肢がないか、コードの保守が非常に困難になります。

  • .c ファイルが 1 つしかないプログラムで、プロトタイプを使用しない場合は、関数を正しい順序で .c ファイルに入れる必要があります。

    => コー​​ド内で関数を使用する場合は、その記述の前に関数のプロトタイプを宣言する必要があります。

  • より大きなプログラムを作成する必要がある場合、コードを別のモジュールに分割します。各モジュールには「パブリック」機能と「プライベート」機能があります。後者は静的であると宣言され (.c ファイルの先頭にプロトタイプを追加する必要があります)、「パブリック」関数プロトタイプは .h ファイル (ヘッダー) になります。

于 2012-12-28T09:01:14.930 に答える
0

プログラムのコンパイルは上から下(つまり、1行目から最後の行)で行われるため、関数宣言(前方宣言とも呼ばれます)が必要です。

これは、関数呼び出しが関数実装の前にある場合にのみ必要です。

ここで宣言された関数がプログラムのどこかで使用されていることをコンパイラーに言及することをお勧めします。

宣言は、ユーザー定義のヘッダーファイルでも実行できます。

于 2012-12-28T11:12:33.283 に答える
0

関数の実装が関数呼び出しの前に配置されている限り、関数は実装自体によって宣言されているため、コードは別の関数宣言なしで機能します。一般に、特に大規模なプログラムの場合は、関数の宣言を行う必要があります。

于 2012-12-28T08:59:40.900 に答える
0

関数のプロトタイプは、その記述のにコードでこの関数を使用する場合にのみ宣言する必要があります。

于 2012-12-28T09:00:55.747 に答える
0

関数宣言は、コンパイラがデータ型の問題をできるだけ早く検出できるようにするのに役立ちます。and を必要とする関数を作成し、floatその代わりに a を渡すと、char場合によっては (たとえば比較のために) それでも機能し、その上にコードをビルドし始めると壊れてしまうことがあります。最終的に、コンピューターはすべてをビット配列として表現するため、2 つの文字を「合計」するか、a を含む 2 つの整数を\0文字列であるかのように連結できますが、将来の保守とデバッグがプログラムを混乱させることになります。

于 2012-12-28T09:01:35.670 に答える