Quel est le but de la syntaxe du pointeur de fonction en C?

EDIT: Il a été souligné que cette question est un peu déroutant. La version courte est: “pourquoi avoir une variable de pointeur séparée (par exemple, fnPtr ) qui pointe vers une fonction (par exemple, fn ) alors que le nom de la fonction fn lui-même, sans arguments, est déjà un pointeur? / EDIT

J’essaie de comprendre quelque chose et pourrais utiliser les commentaires de la communauté concernant les pointeurs de fonction. (Et bien que cela puisse ressembler à une copie d’autres questions sur le sujet, ce n’est vraiment pas le cas, du moins pas que j’ai pu trouver.)

Je comprends le concept d’un pointeur sur une fonction utilisée comme argument d’une autre fonction en tant que rappel … c’est-à-dire dire à fn1 d’utiliser fn2 d’une manière ou d’une autre pendant l’exécution de fn1 . Ce que je ne comprends pas, c’est la syntaxe complexe utilisée dans tout cela. Si fn est une fonction définie, l’appel de fn(...) exécutera la fonction avec les arguments fournis. Cependant, fn utilisé seul est l’adresse de la fonction, c’est-à-dire un pointeur sur la fonction. De plus, fn , &fn et *fn sont tous la même chose. Pourquoi avoir des pointeurs de fonction dédiés et pourquoi créer une nouvelle variable (c’est-à-dire, fnPtr ) qui pointe vers une fonction … le nom de la fonction est déjà son propre pointeur!

Ce code est compilé et fonctionne à chaque fois.

 #include  #include  int fn(int var) { //fn is a function which takes an int and returns an int return var; } int (*fnPtrAmp)(int) = &fn; int (*fnPtr)(int) = fn; int needsCallback(int variable, int callback(int)) { return callback(variable); } int needsCallbackPointer(int variable, int (*callbackPtr)(int)) { return callbackPtr(variable); } int needsCallbackPointerWithDereference(int variable, int (*callbackPtr)(int)) { return (*callbackPtr)(variable); } int main() { printf("%d\n", fn(4)); printf("%d\n", fnPtr(4)); printf("%d\n", (*fnPtr)(4)); printf("%d\n", needsCallback(4,fn)); printf("%d\n", needsCallbackPointer(4,fnPtr)); printf("%d\n", needsCallbackPointer(4,fn)); printf("%d\n", needsCallbackPointer(4,&fn)); printf("%d\n", needsCallbackPointerWithDereference(4,fnPtr)); printf("%d\n", needsCallbackPointerWithDereference(4,fn)); printf("%d\n", needsCallbackPointerWithDereference(4,&fn)); return 0; } 

La syntaxe la plus simple est celle de needsCallback mais cela ne se fait pas n’importe où, c’est toujours needsCallbackPointer et fnPtrAmp . Pourquoi? Avec needsCallback vous n’avez même pas besoin de définir une variable supplémentaire pour être le pointeur de la fonction. Comme je l’ai dit précédemment, le nom de la fonction est son propre pointeur!

Pourrait utiliser quelques commentaires … merci.

  1. Les variables de pointeur de fonction sont utiles lorsque le stream de contrôle qui le suit modifie le pointeur de la fonction (par exemple, choisit un rappel différent).

    Les variables de pointeur de fonction sont également utiles lorsque vous utilisez une liaison d’exécution, où vous ne connaissez pas la fonction au moment de la compilation, mais affectez un pointeur de fonction au moment de l’exécution, par exemple à l’aide de dlsym . Ceci est souvent utilisé dans le contexte des API extensibles (OpenGL est un utilisateur populaire de ce schéma, par exemple) et des plugins.

  2. “La syntaxe la plus simple est celle de needsCallback, mais cela ne se fait pas n’importe où, il faut toujours needCallbackPointer et fnPtrAmp. Why?”: Pour que la déclaration dans le paramètre d’une fonction soit cohérente avec l’apparence d’une déclaration de variable ou typedef.

  3. Une autre question que vous posez est celle de savoir pourquoi *fnPtr fonctionne et pourquoi les parenthèses .

    Eh bien, les parenthèses sont obligatoires, car la fonction call operator () a une priorité supérieure à celle de l’opérateur de déréférencement * ; la fonction est donc appelée en premier lieu, puis la valeur de retour est supprimée. (*fnPtr)() fonctionne autour de cela.

  4. someFunction et &someFunction sont équivalents car les fonctions ne sont pas des citoyens de première classe en C (les fonctions ne sont pas des objects normaux qui peuvent être manipulés, comme un int , par exemple), mais les pointeurs de fonction le sont. Ainsi, un nom de fonction est toujours et insortingnsèquement converti en un pointeur de fonction sur la fonction référencée par ce nom. Notez que vous pouvez appliquer & plusieurs fois à un pointeur de fonction, donnant un pointeur à un pointeur de fonction, pointeur à un pointeur à un pointeur de fonction, etc. Ainsi, il ne se comporte pas de la même manière que * , que vous pouvez utiliser aussi souvent que vous le souhaitez. sur un pointeur de fonction.

  5. *fnPtr fonctionne, car l’opérateur * utilisé sur un pointeur de fonction produit essentiellement le même pointeur. Même raisonnement que 4) – le langage ne contient aucun object fonction. Ainsi, vous ne pouvez pas obtenir un nom de fonction à partir d’un pointeur de fonction, ce qui est impossible.

Je ne sais pas pourquoi ces opérateurs ont été définis pour les noms de fonctions et les pointeurs, respectivement. Peut-être des raisons historiques? Pour la cohérence avec d’autres types de pointeur?

Je soupçonne que la syntaxe sans opérateur a été introduite ultérieurement pour enregistrer le typage, car vous ne pouvez pas utiliser un nom de fonction ni dans un contexte rvalue ni dans un contexte lvalue. Puisqu’il n’y a rien que l’on puisse faire avec un pointeur de fonction non plus (à part le faire circuler. Vous pouvez bien sûr le changer, comme fnPtr++; mais où cela vous fnPtr++; t-il?), Il est très logique d’append la conversion implicite rendant fnPtr() possible, pour enregistrer encore une fois.

(Les deux derniers paragraphes sont de la pure spéculation de ma part.)

La syntaxe du pointeur de fonction en C a deux fonctions

1) Confondre les programmeurs

2) Pour permettre au compilateur de vérifier la syntaxe, les appelants des pointeurs de fonction utilisent les mêmes arguments que les fonctions elles-mêmes.

La seconde est ce qui entraîne le plus de confusion, car si vous avez un pointeur de fonction qui retourne un pointeur, la liaison de la derefence (*) ne fonctionne pas comme prévu et vous devez append des parenthèses supplémentaires.

-UNE