Que signifient les parenthèses autour d'un nom de fonction?

214

Dans l'un de mes fichiers source de projet, j'ai trouvé cette définition de fonction C:

int (foo) (int *bar)
{
    return foo (bar);
}

Remarque: il n'y a pas d'astérisque à côté foo, donc ce n'est pas un pointeur de fonction. Ou est-ce? Que se passe-t-il ici avec l'appel récursif?

user1859094
la source
7
Non, ce n'est pas un pointeur de fonction - c'est toujours une fonction régulière nommée foo.
Nemanja Boric
Est-ce la fonction complète?
asheeshr
2
avez-vous des preuves que cette fonction est utilisée dans un contexte utile?
moooeeeep
1
... ressemble à une fonction factice qui a peut-être été simplement écrite pour voir si elle se compile, dans la source existante, et aurait dû être supprimée. Je le supprimerais (si c'est vraiment ce que fait la fonction), car au mieux ce sera une boucle infinie (je ne suis pas sûr si le compilateur C est autorisé à optimiser cet appel de queue pour sauter), au pire débordement de pile.
hyde
3
Les parenthèses dans les déclarations C aident à rendre le langage ambigu. Vite, c'est quoi a(b);? Déclaration de bcomme variable de type a? Ou un appel à la fonction aavec argument b? La différence est syntaxique, et vous ne pouvez pas savoir de quelle manière même l'analyser sans rechercher les informations de déclaration de a; c'est-à-dire sont ces parenthèses d'appel de fonction postfix, ou des parenthèses facultatives autour d'un déclarant.
Kaz

Réponses:

329

En l’absence de tout préprocesseur en cours, foola signature de

int foo (int *bar)

Le seul contexte dans lequel j'ai vu des gens mettre des parenthèses apparemment inutiles autour des noms de fonction est quand il y a à la fois une fonction et une macro de type fonction avec le même nom, et que le programmeur veut empêcher l'expansion des macros.

Cette pratique peut sembler un peu étrange au début, mais la bibliothèque C crée un précédent en fournissant des macros et des fonctions avec des noms identiques .

L'une de ces paires fonction / macro est isdigit(). La bibliothèque peut le définir comme suit:

/* the macro */
#define isdigit(c) ...

/* the function */
int (isdigit)(int c) /* avoid the macro through the use of parentheses */
{
  return isdigit(c); /* use the macro */
}

Votre fonction est presque identique à celle ci-dessus, donc je pense que c'est aussi ce qui se passe dans votre code.

NPE
la source
2
Cela peut être le cas ici également; Je n'ai pas cherché de macros ... Et je ne savais pas que l'expansion des macros ne se faisait pas entre parenthèses, merci de l'avoir signalé!
user1859094
13
@ user1859094: Au second regard, c'est presque certainement ce qui se passe dans votre code. L' foo(bar)intérieur de la fonction utilise la macro correspondante.
NPE
78
L'extension de macro @ user1859094 a lieu entre parenthèses, mais l'expansion d'une macro de type fonction n'a lieu que si le jeton suivant est une parenthèse gauche (C99, 6.10.3§10), elle foo (int* bar)serait donc remplacée, mais pas (foo) (int *bar)(le jeton suivant après fooest ))
Virgile
4
Comment appeler une telle fonction? Souhaitez-vous l'appeler avec les parenthèses également? Par exemple, cela fonctionnerait-il (isdigit)(5):?
gcochard
4
@Greg: Oui, c'est exactement comme ça que vous l'appeleriez.
NPE
37

Les parenthèses ne changent pas la déclaration - il s'agit simplement de définir une fonction ordinaire appelée foo .

La raison pour laquelle ils ont été utilisés est presque certainement parce qu'il existe une macro de type fonction appelée foodefined:

#define foo(x) ...

L'utilisation (foo)de la déclaration de fonction empêche cette macro d'être développée ici. Donc, ce qui se passe probablement, c'est qu'une fonction foo()est définie avec son corps étendu à partir de la macro de type fonction foo.

caf
la source
5
Belle déduction (bien que l'utilisation de parenthèses à cette fin devrait être punie par la loi).
ugoren
3
@ugoren: l'utilisation de parens autour du nom de la fonction est le seul moyen d'empêcher une expansion de macro pour une macro de type fonction. Parfois, c'est un outil nécessaire.
Michael Burr
7
@MichaelBurr, il y a aussi la possibilité de ne pas avoir de macro et de fonction avec le même nom. Je sais que vous ne pouvez pas toujours tout contrôler, mais si vous arrivez à cette solution, je dirais que quelque chose ne va pas.
ugoren
-3

Les parenthèses n'ont aucun sens.
Le code que vous montrez n'est qu'une récursion infinie.

Lorsque vous définissez un pointeur de fonction, vous voyez parfois d'étranges parenthèses qui signifient quelque chose. Mais ce n'est pas le cas ici.

ugoren
la source
6
Evidemment non; les parenthèses empêchent l'expansion des macros. Voir la réponse acceptée.
Kevin
12
@Kevin, ma réponse concerne le code affiché et est correcte. Dans presque toutes les questions C ici, supposer que des définitions de préprocesseur inconnues peuvent tout changer. Dans ce cas, les réponses qui considèrent le préprocesseur sont en effet meilleures, mais cela ne rend pas la mienne incorrecte.
ugoren