pointeurs de fonctions

pointeurs de fonctions - C - Programmation

Marsh Posté le 25-04-2007 à 21:20:56    

Bonjour,
 
J'aimerai savoir l'utilité des pointeurs de fonctions en C. Je sais vous allez me dire que c'est impensable de pas les utiliser et que y'a que les débutants qui ne les utilisent pas, n'empeche, je ne trouve pas d'exemple concret et suffisamment général pour leur utilisation. Le seul exemple que j'ai trouvé sur le net est celui de tri de chaines de caractères, avec différentes méthodes de tri mais des valeurs de retour identiques des fonctions. Cependant, meme dans ce cas un switch() avec des break (par exemple ? non, bon ok  :sweat: ) serait gérable il me semble. SI c'est juste pour gérer deux ou trois cas dumoins. Enfin....merci de votre réponse par avance, n'hesitez pas si vous avez des exemples  :jap:  

Reply

Marsh Posté le 25-04-2007 à 21:20:56   

Reply

Marsh Posté le 25-04-2007 à 21:48:31    

Bah, toutes les fonctions de callback par exemple.  
Suppose que tu développes un module de saisie de données générique, tu peux après chaque saisie appeler une fonction de contrôle pour cette saisie, ou afficher des champs supplémentaires de saisie, ou des informations suuplémentaires en fonction de ce qui vient d'être saisi.  
Evidemment on rentre dans des choses un peu compliquées.

Reply

Marsh Posté le 26-04-2007 à 00:06:15    

Un site sur les pointeurs de fonctions et les callbacks, peu-têtre qu'il te sera utile...
http://www.newty.de/fpt/index.html (par contre c'est C ET C++)


---------------
You get so used to things the way they are. And I've always been alone. I guess that makes me lonely.
Reply

Marsh Posté le 26-04-2007 à 07:22:36    

Un exemple tout simple, c'est la fonction qsort() de la bibliothèque standard.
Cette fonction permet d'appliquer l'algorithme de tri quicksort sur n'importe quoi. Pour pouvoir faire ça, la fonction admet quatre paramètres : un tableau à trier, le nombre d'éléments et leur taille unitaire (histoire que la fonction sache lire la table), et... un pointeur de fonction.
Ce dernier argument permet de définir une fonction qui sert tout bêtement à comparer deux éléments de la table : la fonction doit prendre deux paramètres (les éléments de la table à comparer), et doit retourner un entier : négatif si le premier élément est inférieur au second, nul s'ils sont égaux, positif dans le dernier cas.
Ce qui nous donne une fonction de tri qui n'a absolument pas besoin de savoir ce qu'elle traite comme donnée, elle est donc générique : qsort() assure l'ordre et le nombre des comparaisons selon un algorithme de tri optimisé, et effectue les actions de tri de la table. Et délègue la comparaison à une fonction écrite par le développeur, permettant de spécialiser la fonction à un emploi précis.

 

Les pointeurs de fonctions sont donc des outils très utiles pour l'écriture de bibliothèques puisque ça permet de créer des fonctions génériques, les spécificités étant laissées à l'utilisateur final.

 

Autre avantage, comme le dit Trap D : les callbacks. Il s'agit d'attribuer à un évènement quelconque (une erreur, l'arrivée d'une donnée, n'importe quoi) une fonction qui se chargera de réagir à cet évènement.
Exemple : la fonction POSIX.1 signal(), qui permet d'attribuer à un signal Unix (évènement balancé au programme par le système, en très gros) une fonction qui effectuera une action dédiée. Par exemple, on peut dire qu'un signal de fin de processus SIGTERM lancera la fonction bidule(), qui se chargera de fermer une connexion réseau ouverte par le programme avant de sortir proprement.

 

Il y a plusieurs autres usages aux pointeurs de fonctions, le cas où je les utilise le plus souvent c'est pour écrire des wrappers.
C'est tout bête : j'écris une fonction "chef de gare" qui va recevoir, par exemple, une structure complexe de données à traiter. Et, selon le type de la donnée (type A, B, C, .... ), je redirige vers une autre fonction qui traitera vraiment la structure.
Plutôt que d'écrire une très longue suite illisible de if...else if.... else if.... etc, j'écris une structure anonyme avec comme élément le type de la donnée, et un pointeur de fonction. Je n'ai plus qu'à boucler dessus, vérifier le type et appeler la fonction correspondante, et l'ajout (ou l'effacement) d'un type de donnée ne prend plus qu'une ligne de paramétrage. La fonction ne fait plus (hors structure anonyme donc) que 10 lignes, à maintenir c'est un poil plus simple.

 

Voila voila.

Message cité 1 fois
Message édité par Elmoricq le 26-04-2007 à 07:24:22
Reply

Marsh Posté le 26-04-2007 à 08:55:43    

Elmoricq a écrit :

Il y a plusieurs autres usages aux pointeurs de fonctions, le cas où je les utilise le plus souvent c'est pour écrire des wrappers.
C'est tout bête : j'écris une fonction "chef de gare" qui va recevoir, par exemple, une structure complexe de données à traiter. Et, selon le type de la donnée (type A, B, C, .... ), je redirige vers une autre fonction qui traitera vraiment la structure.
Plutôt que d'écrire une très longue suite illisible de if...else if.... else if.... etc, j'écris une structure anonyme avec comme élément le type de la donnée, et un pointeur de fonction. Je n'ai plus qu'à boucler dessus, vérifier le type et appeler la fonction correspondante, et l'ajout (ou l'effacement) d'un type de donnée ne prend plus qu'une ligne de paramétrage. La fonction ne fait plus (hors structure anonyme donc) que 10 lignes, à maintenir c'est un poil plus simple.
 
Voila voila.


 
Pour faire suite au message d'Elmoricq, j'ai retrouvé dans les archives du fofo un petit truc que j'avais écrit suite à une discussion sur un exercice.
L'exercice consistait à donner des caractéristiques sur une suite de nombres (dire s'ils sont tous pairs, tous impairs, tous croissants, tous décroissants etc).
J'avais proposé, plutôt que de faire un gros truc bien immonde dans sa rigidité, d'écrire une structure contenant
- un texte explcatif sur la caractéristique recherchée
- le résultat attendu
- un pointeur sur une fonction chargée de vérifier que l'ensemble des nombres répond bien aux caractéristiques attendues
Ce qui permettrait ensuite l'évolutivité du truc => rajouter un nouveau test consisterait juste à rajouter la fonction de vérification de ce test et l'intégrer dans l'ensemble des fonctions déjà exécutées de façon automatiques
 
Voici le code source du truc

Code :
  1. #include <sys/types.h>
  2. #include <stdio.h>
  3. #define NB   (3)   // Nombre d'éléments
  4. // Structure qui gère la question et la vérification de la réponse
  5. typedef struct {
  6. char *txt;     // Texte à afficher
  7. int (*verif)(int*);     // Fonction de vérification
  8. int result;     // Résultat attendu
  9. } t_question;      // Type créé
  10. // Prototype des fonctions utilisées
  11. int croissance(int*);     // Vérifie la croissance
  12. int impair(int*);      // Compte combien il y a d'impair
  13. int egalite(int*);      // Vérifie tous égaux
  14. int different(int*);      // Vérifie tous différents
  15. int main()
  16. {
  17. int tabNB[NB];     // Tableau des nombres
  18. int nb_rep;     // Nb réponses
  19. size_t i;      // Indice de boucle
  20. static t_question tabQuestion[]={    // Tableau des questions
  21.  {"Vérification croissance", croissance, 1},
  22.  {"Nombres tous impairs", impair, NB},
  23.  {"Nombres tous pairs", impair, 0},
  24.  {"Nombres tous égaux", egalite, 1},
  25.  {"Nombres tous différents", different, 1},
  26.  {NULL, NULL}
  27. };
  28. t_question *ptQuestion;    // Ptr balayage des questions
  29. // On fait saisir les nombres
  30. for (i=0; i < NB; i++)
  31. {
  32.  printf("Entrez le nombre %d :", i + 1);
  33.  fflush(stdout);
  34.  scanf("%d", &tabNB[i]);
  35.  getchar();
  36. }
  37. // Balayage des questions
  38. for (ptQuestion=tabQuestion, nb_rep=0; ptQuestion->prompt != NULL; ptQuestion++, nb_rep++)
  39. {
  40.  // On affiche l'action et son résultat
  41.  printf("%s %s\n", ptQuestion->txt, (ptQuestion->verif)(tabNB) == ptQuestion->result ?"ok" :"faux" );
  42. }
  43. return 0;
  44. }
  45. // Fonction qui vérifie la croissance
  46. int croissance(int *tabNB)
  47. {
  48. size_t i;      // Indice de boucle
  49. // On balaye les nombres
  50. for (i=1; i < NB; i++)
  51. {
  52.  // On regarde si la croissance s'interromp
  53.  if (tabNB[i] <= tabNB[i - 1])
  54.   // La croissance n'est plus respectée
  55.   return 0;
  56. }
  57. // Tous croissants
  58. return 1;
  59. }
  60. // Fonction qui compte le nombre d'impairs
  61. int impair(int *tabNB)
  62. {
  63. size_t i;      // Indice de boucle
  64. int cpt;      // Compteur des impairs
  65. // On balaye les nombres
  66. cpt=0;
  67. for (i=0; i < NB; i++)
  68. {
  69.  if ((tabNB[i] % 2) == 1)
  70.   // Le nombre est impair
  71.   cpt++;
  72. }
  73. // On renvoie le résultat
  74. return cpt;
  75. }
  76. // Fonction qui vérifie qu'ils sont tous égaux
  77. int egalite(int *tabNB)
  78. {
  79. size_t i;      // Indice de boucle
  80. // On balaye les nombres
  81. for (i=1; i < NB; i++)
  82. {
  83.  // On regarde si le nombre est différent du premier
  84.  if (tabNB[i] != tabNB[0])
  85.   // L'égalité n'est plus respectée
  86.   return 0;
  87. }
  88. // Tous égaux
  89. return 1;
  90. }
  91. // Fonction qui vérifie qu'ils sont tous différents
  92. int different(int *tabNB)
  93. {
  94. size_t i;      // Indice de boucle
  95. size_t j;      // Indice de boucle
  96. // On balaye les nombres
  97. for (i=1; i < NB; i++)
  98. {
  99.  // On balaye les nombres situés avant celui en cours
  100.  for (j=0; j < i; j++)
  101.  {
  102.   // On regarde si le nombre est égal à un des nombres précédents
  103.   if (tabNB[i] == tabNB[j])
  104.    // L'inégalité n'est plus respectée
  105.    return 0;
  106.  }
  107. }
  108. // Tous inégaux
  109. return 1;
  110. }


 
Et voilà - Si on veut rajouter un traitement à faire sur le tableau de nombres, de:
- écrire la fonction de traitement
- rajouter le texte explicatif, le pointeur sur la fonction et le résultat attendu dans le tabQuestion
- prototyper la fonction avant le main
- et recompiler
 
Si on a envie de s'amuser sur 4, 5 ou 100 nombres, il suffit de modifier la valeur du "#define NB  (3)" et recompiler
 
La compréhension du pointeur sur fonctions est un grand pas en avant vers l'objet


Message édité par Sve@r le 26-04-2007 à 09:00:35

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 26-04-2007 à 10:07:16    

in_your_phion a écrit :

J'aimerai savoir l'utilité des pointeurs de fonctions en C.


En complément de ce qui a été dit :  
 
http://mapage.noos.fr/emdel/complog.htm
 


---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 26-04-2007 à 14:24:35    

:love:  :love: Merci pour vos réponses!  :love:  :love:

 

Sve@r, ton code est un exemple qui me parle bien  :jap: "La compréhension du pointeur sur fonctions est un grand pas en avant vers l'objet", je suis sur que Douste dirait "aneffet"


Message édité par in_your_phion le 26-04-2007 à 14:26:47
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed