52

わかりました、この件に関してさまざまな意見を聞いたので、正しく理解していることを確認したいだけです。

C++ の場合

宣言void f();とはまったくvoid f(void);同じことを意味し、関数fはパラメーターを取りません。定義についても同様です。

C の場合

宣言とは、パラメータを取らないことをvoid f(void);意味します。f

宣言void f();とは、関数fにパラメーターがある場合とない場合があることを意味します。ある場合、それらがどのような種類のパラメーターであるか、またはそれらがいくつあるかはわかりません。省略記号と同じではないことに注意してください。使用できませんva_list

ここからが興味深いところです。

ケース1

宣言:

void f();

意味:

void f(int a, int b, float c)
{
   //...
}

ケース 2

宣言:

void f();

意味:

void f()
{
   //...
}

質問:

fケース 1 とケース 2で、正しい引数、間違った引数、および引数なしで呼び出した場合、コンパイル時に何が起こるでしょうか? 実行時に何が起こるか?

追加の質問:

引数付きで宣言fし、引数なしで定義すると、違いはありますか? 関数本体から引数をアドレス指定できるようにする必要がありますか?

4

4 に答える 4

61

その他の用語 (C++ ではなく C): 関数のプロトタイプは、その引数の型を宣言します。それ以外の場合、関数にはプロトタイプがありません。

void f();                      // Declaration, but not a prototype
void f(void);                  // Declaration and prototype
void f(int a, int b, float c); // Declaration and prototype

プロトタイプではない宣言は、K&R C の時代からの ANSI C 以前の名残りです。古いスタイルの宣言を使用する唯一の理由は、古いコードとのバイナリ互換性を維持することです。たとえば、GTK 2 には、プロトタイプのない関数宣言があります。これは偶然にもありますが、バイナリを壊さずに削除することはできません。C99 標準コメント:

6.11.6 関数宣言子

括弧が空の関数宣言子 (プロトタイプ形式のパラメーター型宣言子ではない) の使用は廃止予定の機能です。

推奨: GCC/Clang のすべての C コードを、通常の に加えて-Wstrict-prototypesandでコンパイルすることをお勧めします。-Wmissing-prototypes-Wall -Wextra

何が起こるのですか

void f(); // declaration
void f(int a, int b, float c) { } // ERROR

宣言が関数本体と一致しません! これは実際にはコンパイル時floatエラーであり、プロトタイプのない関数では引数を持てないためです。プロトタイプ化されていない関数でa を使用できない理由はfloat、そのような関数を呼び出すと、特定のデフォルト プロモーションを使用してすべての引数が昇格されるためです。固定例を次に示します。

void f();

void g()
{
    char a;
    int b;
    float c;
    f(a, b, c);
}

このプログラムでaは、 はint1に昇進し、cに昇格しdoubleます。したがって、 の定義f()は次のようにする必要があります。

void f(int a, int b, double c)
{
    ...
}

C99 6.7.6 パラグラフ 15 を参照してください。

一方の型にパラメーター型リストがあり、もう一方の型が、関数定義の一部ではなく、空の識別子リストを含む関数宣言子によって指定されている場合、パラメーター リストには省略記号終端記号がなく、各パラメーターの型はデフォルトの引数昇格を適用した結果の型と互換性があります。

答え 1

fケース 1 とケース 2で、正しい引数、間違った引数、および引数なしで呼び出した場合、コンパイル時に何が起こるでしょうか? 実行時に何が起こるか?

を呼び出すf()と、パラメータはデフォルトの昇格を使用して昇格されます。昇格した型が の実際のパラメーターの型と一致する場合、f()すべて問題ありません。それらが一致しない場合、おそらくコンパイルされますが、未定義の動作が発生することは間違いありません。

「未定義の動作」とは、「何が起こるかについて保証しない」という仕様上の言葉です。プログラムがクラッシュするかもしれませんし、問題なく動作するかもしれませんし、義理の家族を夕食に招待するかもしれません。

コンパイル時に診断を取得するには、2 つの方法があります。モジュール間の静的解析機能を備えた高度なコンパイラを使用している場合は、おそらくエラー メッセージが表示されます。-- を使用して、GCC でプロトタイプ化されていない関数宣言のメッセージを取得することもできます-Wstrict-prototypes(GTK 2 を使用するファイルを除く)。

答え 2

引数付きで宣言fし、引数なしで定義すると、違いはありますか? 関数本体から引数をアドレス指定できるようにする必要がありますか?

コンパイルされるべきではありません。

例外

実際には、関数の引数が関数定義と一致しないことが許されるケースが 2 つあります。

  1. char *を期待する関数に渡すことは問題ありませんvoid *

  2. 値が両方の型で表現可能である限り (つまり、負ではなく、サインタイプ)。

脚注

1 : が に昇格する可能性はありますが、これは非常にまれです。charunsigned int

于 2012-11-10T05:33:38.863 に答える
7

C99以降を使用している場合、すべてが本当に議論の余地があります(古い組み込みシステムなどに行き詰まっていない限り、おそらくもっと新しいものを使用する必要があります)。

C99/C11 セクション6.11.6 Future language directions, Function declaratorsの状態:

括弧が空の関数宣言子 (プロトタイプ形式のパラメーター型宣言子ではない) の使用は廃止予定の機能です。

void f();したがって、のようなものを完全に使用することは避けるべきです。

パラメータを取る場合は、それらをリストして、適切なプロトタイプを形成します。voidそうでない場合は、パラメータを取らないことを明確に示すために使用します。

于 2012-11-10T05:45:38.310 に答える
3

C ++では、f()とf(void)は同じです。

Cでは、これらは異なり、f()関数の呼び出し中に任意の数の引数を渡すことができますが、f(void)では引数を渡すことはできません。

于 2012-11-10T10:06:38.907 に答える
-2

純粋な C では、これにより次のエラーが発生します。error C2084: function 'void __cdecl f(void )' already has a body

void f(void);
void f();

int main() {
  f(10);
  f(10.10);
  f("ten");

  return 0;
}

void f(void) {

}

void f() {

}

fvoid.c 行 (19) : エラー C2084: 関数 'void __cdecl f(void )' には既に本体があります

しかし、純粋なC++ では、エラーなしでコンパイルされます。

関数のオーバーロード (C++ のみ、C にはオーバーロードはありません)

同じスコープ内で名前 f を持つ複数の関数を宣言することにより、関数名 f をオーバーロードします。f の宣言は、引数リスト内の引数の型および/または数によって互いに異なっていなければなりません。f という名前のオーバーロードされた関数を呼び出すと、関数呼び出しの引数リストと、名前 f のオーバーロードされた各候補関数のパラメーター リストを比較して、正しい関数が選択されます。

例:

#include <iostream>
using namespace std;

void f(int i);
void f(double  f);
void f(char* c);


int main() {
  f(10);
  f(10.10);
  f("ten");

  return 0;
}

void f(int i) {
  cout << " Here is int " << i << endl;
}
void f(double  f) {
  cout << " Here is float " << f << endl;
}

void f(char* c) {
  cout << " Here is char* " << c << endl;
}

出力:

Here is int 10
Here is float 10.1
Here is char* ten
于 2012-11-10T06:09:40.537 に答える