web-dev-qa-db-ja.com

パラメータ名は省略、C ++ vs C

C++では、状況によってはパラメーターの名前が省略される傾向があります。しかし、Cでは、パラメーターの名前を省略したときにエラーが発生しました。

これがコードです:

void foo(int);  //forward-decl, it's OK to omit the parameter's name, in both C++ and C

int main()
{
    foo(0);
    return 0;
}

void foo(int)  //definition in C, it cannot compile with gcc
{
    printf("in foo\n");
}

void foo(int)  //definition in C++, it can compile with g++
{
    cout << "in foo" << endl;
}

何故ですか? C関数の定義でパラメーターの名前を省略できませんか?

40
Alcott

いいえ、Cでは関数定義のパラメーターの識別子を省略できません。

C99標準は言う:

[6.9.1.5]宣言子にパラメーター型リストが含まれている場合、各型の宣言には識別子が含まれます。識別子。宣言リストは後に続きません。

C++ 14標準は次のように述べています。

[8.3.5.11] 識別子はオプションでパラメーター名として指定できます。関数定義に存在する場合、パラメーターに名前を付けます(「仮引数」と呼ばれることもあります)。[注:特に、パラメーター名も関数定義ではオプションと、異なる宣言でパラメーターに使用される名前と関数の定義は同じである必要はありません。]

35
adl

その理由は、それがそれぞれの言語標準が言うことですが、違いの根拠があります。

パラメータの名前を指定しない場合、関数はそのパラメータを参照できません。

Cでは、関数がそのパラメーターの1つを無視する場合、通常は宣言と定義から削除するだけで、どの呼び出しにも渡さないのが理にかなっています。例外はコールバック関数であり、関数のコレクションはすべて同じタイプである必要がありますが、すべての関数が必ずしもパラメーターを使用する必要はありません。しかし、それはあまり一般的なシナリオではありません。

C++では、関数がいくつかの親クラスで定義された関数から派生している場合、子関数がパラメーター値のいずれかを使用していない場合でも、関数は親と同じシグニチャーを持つ必要があります。

(これはデフォルトのパラメーターとは関係がないことに注意してください。C++のパラメーターにデフォルト値がある場合、呼び出し元は明示的に渡す必要はありませんが、それを参照する場合は、関数定義で名前を指定する必要があります。 )

17
Keith Thompson

純粋に実用的なレベルで、私はこれを毎日扱っています。これまでの最善の解決策は、プリプロセッサを使用することです。私の一般的なヘッダーファイルには以下が含まれます。

//-------------------------------------------------------------------------
//  Suppress nuisance compiler warnings. Yes, each compiler can already 
//  do this, each differently! VC9 has its UNREFERENCED_PARAMETER(),
//  which is almost the same as the SUPPRESS_UNUSED_WARNING() below.
//
//  We append _UNUSED to the variable name, because the dumb gcc compiler
//  doesn't bother to tell you if you erroneously _use_ something flagged
//  with __attribute__((unused)). So we are forced to *mangle* the name.
//-------------------------------------------------------------------------
#if defined(__cplusplus)
#define UNUSED(x)       // = nothing
#Elif defined(__GNUC__)
#define UNUSED(x)       x##_UNUSED __attribute__((unused))
#else
#define UNUSED(x)       x##_UNUSED
#endif

UNUSEDの使用例は次のとおりです。

void foo(int UNUSED(bar)) {}

たとえば、assert()またはdebugステートメントなどで、実際にパラメーターを参照する必要がある場合があります。あなたはそれを行うことができます:

#define USED_UNUSED(x)  x##_UNUSED // for assert(), debug, etc

また、以下も役立ちます。

#define UNUSED_FUNCTION(x) inline static x##_UNUSED // "inline" for GCC warning
#define SUPPRESS_UNUSED_WARNING(x) (void)(x) // cf. MSVC UNREFERENCED_PARAMETER

例:

UNUSED_FUNCTION(int myFunction)(int myArg) { ...etc... }

そして:

void foo(int bar) {
#ifdef XXX
   // ... (some code using bar)
#else
   SUPPRESS_UNUSED_WARNING(bar);
#endif
}
5
Joseph Quinsey

関数プロトタイプではパラメーター名を省略できますが、関数実装で宣言する必要があります。たとえば、これはGCC 4.6.1でコンパイルおよび実行できます。

void foo(int, int);

void foo(int value, int secondValue)
{
    printf("In foo with value %d and %d!\n", value, secondValue);
}

int main(int argc, char **argv)
{
    foo(10, 15);
    return 0;
}

出力:In foo with value 10 and 15!

理由について(標準でそう言われている以外):C++では、すべての引数を使用せずに関数を呼び出すことができますが、Cではできません。 Cの関数にすべての引数を指定しない場合、コンパイラーはerror: too few arguments to function 'foo'をスローします

4
Rabbit