web-dev-qa-db-fra.com

nom de paramètre omis, C ++ vs C

En C++, j'ai tendance à omettre le nom du paramètre dans certaines circonstances. Mais en C, j'ai eu une erreur quand j'ai omis le nom du paramètre.

Voici le code:

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;
}

Pourquoi donc? Ne puis-je pas omettre le nom du paramètre dans la définition de la fonction C?

40
Alcott

Non, en C, vous ne pouvez pas omettre les identifiants des paramètres dans les définitions de fonction.

La norme C99 dit:

[6.9.1.5] Si le déclarant comprend une liste de types de paramètres, la déclaration de chaque paramètre doit inclure un identifiant, sauf dans le cas particulier d'une liste de paramètres constituée d'un seul paramètre de type void, auquel cas il ne doit pas y avoir de identifiant. Aucune liste de déclarations ne doit suivre.

La norme C++ 14 dit:

[8.3.5.11] n identifiant peut éventuellement être fourni comme nom de paramètre; s'il est présent dans une définition de fonction, il nomme un paramètre (parfois appelé "argument formel"). [Remarque: En particulier, les noms de paramètre sont également facultatif dans les définitions de fonction et les noms utilisés pour un paramètre dans différentes déclarations et la définition d'une fonction ne doivent pas nécessairement être les mêmes.]

35
adl

La raison en est que c'est ce que disent les normes linguistiques respectives, mais il y a une justification à la différence.

Si vous ne fournissez pas de nom pour un paramètre, la fonction ne peut pas faire référence à ce paramètre.

En C, si une fonction ignore l'un de ses paramètres, il est généralement logique de le supprimer de la déclaration et de la définition et de ne le passer dans aucun appel. Une exception peut être une fonction de rappel, où une collection de fonctions doit toutes être du même type mais toutes n'utilisent pas nécessairement leurs paramètres. Mais ce n'est pas un scénario très courant.

En C++, si la fonction est dérivée d'une fonction définie dans une classe parent, elle doit avoir la même signature que le parent, même si la fonction enfant n'a aucune utilité pour l'une des valeurs de paramètre.

(Notez que cela n'est pas lié aux paramètres par défaut; si un paramètre en C++ a une valeur par défaut, l'appelant n'a pas à la transmettre explicitement, mais la définition de la fonction doit toujours fournir un nom s'il veut s'y référer. )

17
Keith Thompson

Sur un plan purement pratique, je m'en occupe quotidiennement. La meilleure solution à ce jour est d'utiliser le pré-processeur. Mon fichier d'en-tête commun contient:

//-------------------------------------------------------------------------
//  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

Un exemple d'utilisation de UNUSED est:

void foo(int UNUSED(bar)) {}

Parfois, vous devez réellement vous référer au paramètre, par exemple dans une instruction assert () ou debug. Vous pouvez le faire via:

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

En outre, les éléments suivants sont utiles:

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

Exemples:

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

et:

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

Vous pouvez omettre le nom du paramètre dans le prototype de fonction, mais vous devez le déclarer dans l'implémentation de la fonction. Par exemple, cela compile et fonctionne très bien sous 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;
}

Les sorties: In foo with value 10 and 15!

Quant à savoir pourquoi (autre que parce que les normes le disent): C++ vous permet d'appeler une fonction sans utiliser tous les arguments, contrairement à C. Si vous ne fournissez pas tous les arguments d'une fonction en C, le compilateur lancera error: too few arguments to function 'foo'

4
Rabbit