32 votes

Indicateurs de fonction en C - nature et utilisation

Je viens de lire une question intéressante ici qui me fait me demander à propos de deux choses:

  1. Pourquoi devrait-on comparer des pointeurs de fonction, étant donné que par la conception, les fonctions de l'unicité est assurée par leurs noms différents?
  2. Le compilateur voir des pointeurs de fonction spéciale pointeurs? Je veux dire qu'il ne les voir comme, disons, des pointeurs vers des void * ou tient-il des informations plus riches (comme le type de retour, le nombre d'arguments et les arguments de types différents?)

36voto

StoryTeller Points 6139

Pourquoi devrait-on comparer les pointeurs de fonction? Voici un exemple:

#include <stdbool.h>

/*
 * Register a function to be executed on event. A function may only be registered once.
 * Input:
 *   arg - function pointer
 * Returns:
 *   true on successful registration, false if the function is already registered.
 */
bool register_function_for_event(void (*arg)(void));

/*
 * Un-register a function previously registered for execution on event.
 * Input:
 *   arg - function pointer
 * Returns:
 *   true on successful un-registration, false if the function was not registered.
 */
bool unregister_function_for_event(void (*arg)(void));

Le corps de l' register_function_for_event , il ne voit qu' arg. Il ne peut pas voir le nom de la fonction. Il faut comparer les pointeurs de fonction de rapport de quelqu'un, c'est d'enregistrer la même fonction deux fois.

Et si vous voulez soutenir quelque chose comme unregister_function_for_event pour compléter ce qui précède, la seule information que vous avez est la fonction de l'adresse. Si vous avez de nouveau besoin de passer, et de comparer contre elle, pour permettre le démontage.

Comme pour les plus riches d'informations, oui. Lorsque le type de fonction contient un prototype, c'est en partie le type statique de l'information. Vous l'esprit qu'en C, un pointeur de fonction peut être déclarée sans un prototype, mais c'est la vétusté des fonctionnalité.

19voto

  1. Pourquoi quelqu'un pour comparer les pointeurs? Envisagez le scénario suivant -

    Vous disposez d'un tableau de pointeurs de fonction, dire que c'est un appel de retour de la chaîne et vous avez besoin d'appeler chacun d'entre eux. La liste se termine avec un NULL (ou sentinelles) pointeur de fonction. Vous avez besoin de comparer, si vous avez atteint la fin de la liste en les comparant avec ce sentinel pointeur. Aussi, cette affaire justifie précédente OPs préoccupation que les différentes fonctions sont différents pointeurs même si elles sont similaires.

  2. Le compilateur de les voir différemment? Oui. Le type de données comprennent toutes les informations sur les arguments et le type de retour.

    Par exemple, le code suivant va/doit être rejetée par le compilateur

    void foo(int a);
    void (*bar)(long) = foo; // Without an explicit cast
    

18voto

R Sahu Points 24027
  1. Pourquoi devrait-on comparer des pointeurs de fonction, étant donné que par la conception, les fonctions de l'unicité est assurée par leurs noms différents?

Un pointeur de fonction peuvent pointer vers des fonctions différentes à des moments différents dans un programme.

Si vous avez une variable comme

void (*fptr)(int);

il peut pointer vers n'importe quelle fonction qui accepte un int en entrée et renvoie void.

Disons que vous avez:

void function1(int)
{
}

void function2(int)
{
}

Vous pouvez utiliser:

fptr = function1;
foo(fptr);

ou:

fptr = function2;
foo(fptr);

Vous pourriez vouloir faire des choses différentes en foo selon que l' fptr de points à une fonction ou à un autre. D'où la nécessité de:

if ( fptr == function1 )
{
    // Do stuff 1
}
else
{
    // Do stuff 2
}
  1. Le compilateur voir des pointeurs de fonction spéciale pointeurs? Je veux dire qu'il ne les voir comme, disons, les pointeurs de type void * ou ne détient des informations plus riches (comme le type de retour, le nombre d'arguments et les arguments de types différents?)

Oui, des pointeurs de fonction spéciales sont des pointeurs, différente de pointeurs vers des objets.

Le type d'un pointeur de fonction dispose de tous les renseignements au moment de la compilation. Donc, donner un pointeur de fonction, le compilateur va avoir toutes les informations le type de retour, le nombre d'arguments et de leurs types.

5voto

Serge Ballesta Points 12850

La partie classique sur les pointeurs de fonction est déjà discuté dans une autre réponse:

  • Comme d'autres pointeurs, pointeurs de fonction peuvent pointer vers des objets différents à des moments différents de sorte qu'en comparant entre eux peut faire sens.
  • Les pointeurs de fonction sont spéciaux et ne doivent pas être stockées dans d'autres types pointeur (même pas void * , et même en langage C).
  • La partie riche (signature de fonction) est stocké dans le type de fonction - la raison pour laquelle la phrase ci-dessus.

Mais C est un (ancien) de la fonction de déclaration de mode. En plus de la pleine prototype de mode qui déclare le type de retour et le type pour tous les paramètres, C peut utiliser ce qu'on appelle de la liste des paramètres de mode qui est l'ancienne K&R mode. Dans ce mode, la déclaration que déclare le type de retour:

int (*fptr)();

En C, il déclare un pointeur de fonction retournant un int et d'accepter l'ajout de paramètres arbitraires. Simplement, il aura un comportement indéterminé (UB) pour l'utiliser avec un mauvais paramètre de la liste.

Donc c'est légal, le code C:

#include <stdio.h>
#include <string.h>

int add2(int a, int b) {
    return a + b;
}
int add3(int a, int b, int c) {
    return a + b + c;
}

int(*fptr)();
int main() {
    fptr = add2;
    printf("%d\n", fptr(1, 2));
    fptr = add3;
    printf("%d\n", fptr(1, 2, 3));
    /* fprintf("%d\n", fptr(1, 2)); Would be UB */
    return 0;
}

Ne fais pas semblant je vous conseille de le faire! Il est désormais considéré comme la vétusté des fonction et devraient être évités. Je suis seulement en garde contre elle. À mon humble avis, ça ne pouvait être qu'exceptionnel acceptable des cas d'utilisation.

2voto

Mehrdad Points 70493

Imaginez comment vous pourriez mettre en œuvre des fonctionnalités similaires à celles de l' WNDCLASS?

Il a un lpszClassName de distinguer les classes de fenêtre les uns des autres, mais disons que vous n'avez pas besoin (ou ne pas avoir) une chaîne de caractères disponible pour distinguer les différentes classes les unes des autres.

Ce que vous n' avez est la classe de la fenêtre de la procédure lpfnWndProc (de type WindowProc).

Alors maintenant, que feriez-vous si quelqu'un vous appelle RegisterClass deux fois avec le même lpfnWndProc?
Vous avez besoin de détecter les ré-enregistrements de la même classe d'une certaine façon et renvoie une erreur.

C'est un cas où la chose logique à faire est de comparer les fonctions de rappel.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X