Comment typedef fonctionne pour les pointeurs de fonction

Je pense que je souffre peut-être de la maladie redoutée des “programmeurs accidentels”, du moins en ce qui concerne les libellés de caractères et les indicateurs de fonction. J’ai donc expérimenté toutes sortes de combinaisons impliquant ces parsings pour parsingr les résultats en fonction de tous les résultats obtenus.

Mais comme je continuais à essayer différentes combinaisons, au lieu d’parsingr les résultats, je suis maintenant perdu dans le processus.

J’espère que vous m’aiderez à comprendre ce gâchis.

Premier exemple de code

typedef void (print)(void); void do_something (void) { printf("Hello World\n"); } print *pr; pr = &do_something; pr(); // Hello World 

Deuxième exemple de code

 typedef void (print)(void); void do_something (void) { printf("Hello World\n"); } print *pr; pr = do_something; pr(); // Hello World 

Comment fonctionnent les deux exemples de code ci-dessus, c’est comme si ‘&’ n’avait aucun effet sur le nom de la fonction

troisième exemple de code

 typedef void (print)(void); void do_something (void) { printf("Hello World\n"); } print pr; pr = do_something; // comstack error pr = &do_something; // comstack error pr(); 

J’espérais que l’un des mandats ci-dessus fonctionnerait ici, mais bon sang! Je ne comprends vraiment pas les indicateurs de fonction (et peut-être aussi typedef).

L’adresse d’un nom de fonction et le nom de fonction en clair signifient la même chose, donc & n’a pas d’effet sur le nom de la fonction.

De même, lors de l’utilisation de pointeurs de fonction, la déréférencement multiple n’est pas un problème:

 #include  typedef void print(void); static void dosomething(void) { printf("Hello World\n"); } int main(void) { print *f1 = dosomething; print *f2 = &dosomething; f2(); (f1)(); (*f1)(); (**f2)(); (***f1)(); (****f2)(); (*****f1)(); } 

Cela se comstack proprement sous:

 gcc -O3 -g -Wall -Wextra -Werror -Wmissing-prototypes -Wssortingct-prototypes \ -Wold-style-definition -std=c99 xx.c -o xx 

Je ne prétends pas que plusieurs écanvass est un bon style; ce n’est pas. C’est «étrange et (oui, vous pouvez le dire) pervers». Une seule suffit (et la seule écanvas s’adresse principalement aux personnes comme moi qui ont appris à programmer en C avant que la norme ne dise “c’est OK pour appeler une fonction via un pointeur sans utiliser la (*pointer_to_function)(arg1, arg2) ; vous peut simplement écrire pointer_to_function(arg1, arg2) si vous aimez “). Oui, c’est bizarre. Non, aucun autre type (ou classe de types) ne présente le même comportement, Dieu merci.

La chose à propos des pointeurs de fonction est qu’ils sont des pointeurs de fonction ! 🙂 Voici comment vous obtenez votre troisième échantillon au travail:

 #include  typedef void (*print)(void); // ^ void do_something (void) { printf("Hello World\n"); } int main (void) { print pr; pr = do_something; // &do_something would also work. pr(); return 0; } 

Que vous funcName ou &funcName , peu importe (en C au moins). La section 6.3.2.1 Lvalues, arrays and function designators indique:

Un indicateur de fonction est une expression ayant le type de fonction. Sauf s’il s’agit de l’opérande de l’opérateur sizeof ou de l’opérateur unary &, un indicateur de fonction de type “type renvoyant une fonction” est converti en une expression de type “pointeur vers un type renvoyant une fonction”.

Il s’avère que, en C / C ++, funcname et &funcname donneront l’adresse de funcname et pourront être affectés à une variable de pointeur de fonction. Ceci est en fait juste une bizarrerie de la façon dont la syntaxe a été conçue pour la ou les langues.

Comme C, C ++ a un pointeur sur des fonctions: void (*)() par exemple, est un pointeur sur une fonction qui ne prend aucun argument et ne renvoie aucune valeur. Cependant, C ++ a également introduit des références aux fonctions void (&)() et il existe des conversions implicites entre les deux (bien que je ne me souvienne pas exactement des règles).

Donc:

  • funcname est une référence à la fonction
  • &funcname est un pointeur sur une fonction

Notez que prendre l’adresse (ou une référence à) une fonction qui est surchargée nécessite un static_cast du type exact (pour résoudre la surcharge).