web-dev-qa-db-fra.com

Pointeur de fonction de passage

Je suis un peu confus quant à la façon dont je passerais un pointeur à une fonction de pointeur. J'ai une fonction qui prend un pointeur vers une fonction que je comprends sans problème (ExecBlock). Mais on me donne un autre prototype de fonction (ExecBlock2) qui prend le pointeur déréférencé (je ne sais pas exactement de quoi il s'agit) et prend également l'argument si la fonction passée en a. Si quelqu'un pouvait expliquer la priorité et exactement ce que le déréférencement ferait une fonction de pointeur. N'est-ce pas simplement passer la fonction elle-même?. Que fait (void *) dans ce cas?

int ExecBlock (void (*f) (void), int isSet)
{
    return ExecBlock2( HOW TO PASS HERE? , NULL, isSet);
}

int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
{
    ... more code
}
18
ThePedestrian
void (*f) (void)

signifie un pointeur pour fonctionner sans aucun argument renvoyant void.

void *(*f)(void *)

signifie pointeur pour fonctionner en prenant un pointeur vide et en renvoyant un pointeur vide.

Comme les types sont différents, le compilateur ne vous permettra pas de passer l'un à l'autre sans transtyper. (Notez que le casting n'est pas vraiment la bonne réponse ici, et comme le souligne @detly, entraîne un comportement indéfini.)

En ce qui concerne le déréférencement de pointeurs vers des fonctions, vous n'avez pas besoin de mettre explicitement un "*" devant un pointeur de fonction pour l'appeler. Par exemple, vous pouvez appeler votre pointeur de fonction f simplement en faisant

f();

Un exemple de pointeur de fonction

Supposons que vous ayez une fonction f, que vous aimeriez transmettre à une fonction appelée takes_a_function. takes_a_function Aura probablement un type comme

void takes_a_function(void (*f)(void *data), void *data);

Remarquez comment il y a deux arguments pour takes_a_function, Un pointeur de fonction et un pointeur vide pour certaines données. Notez également que la fonction f prend un pointeur void comme argument. L'idée est que vous pouvez transmettre les données à takes_a_function Et les transmettre à f. Par exemple, takes_a_function Pourrait être défini comme

void takes_a_function(void (*f)(void *), void *data) {
  f(data);
}

Maintenant, écrivons une fonction à passer à takes_a_function. Notre fonction affichera simplement un int qui lui est passé.

void prints_an_int(void *data) {
  // The idiom for converting a void pointer to another kind
  // of pointer.  NO NEED TO CAST.  Note this behavior is only
  // defined if the pointer data really does point to an int.
  int *i = data;
  printf("%d", *i);
}

int i = 0;
takes_a_function(prints_an_int, &i);

Quelques points clés sur cet exemple:

  • prints_an_int A le même type que le pointeur de fonction attendu par takes_a_function. Pas besoin de lancer.
  • Il n'est pas nécessaire d'utiliser l'opérateur & Pour créer une référence à une fonction. C'est pourquoi nous pouvons passer directement de prints_an_int À takes_a_function. Mais on pourrait aussi dire takes_a_function(&prints_an_int, &i), et ce serait pareil.
  • void* Signifie essentiellement "pointeur vers un type inconnu". Pour en faire quoi que ce soit, vous devez affecter une variable de type void* À une autre variable de pointeur dont vous attendez le type. Cela n'est garanti que si vous passez le type de pointeur correct! Dans cet exemple, nous pouvons affecter data à un int*, Car les données pointent vraiment vers un int. Si vous voulez plus de données qu'un simple entier, un modèle courant consiste à créer votre propre type de structure qui inclut tous les champs que vous souhaitez, et à passer à la place.
  • Dans un cas particulier, le compilateur ne nécessite pas de transtypage lors de l'affectation de pointeurs void à d'autres pointeurs et vice-versa. Mais encore une fois, vous n'obtenez un comportement défini que si vous convertissez éventuellement un pointeur void vers le type correct.
37
Chris Rice

Par exemple, vous avez une fonction

void * abc(void *)
{
//... 
}

int ExecBlock (void (*f) (void), int isSet)
    {
        return ExecBlock2( abc , NULL, isSet); //use name of the function which have void * as parameter type list and return type  void *   
        }

int ExecBlock2(void *(*f)(void *), void *arg, int isSet)
{
    ... more code
}  

Voir pointeurs de fonction

1
Gangadhar