Programmation générique

Programmation générique - C - Programmation

Marsh Posté le 11-06-2007 à 12:02:35    

Bonjour,
 
Je voudrai être sûr d'avoir compris les pointeurs de fonctions et la généricité en C. Pour être sûr d'avoir compris, est ce que quelqu'un qui connait bien le C pourrait me dire si ce que je dis est bien (c'est bien :o ) ou mal (bahhhh c'est mal  :o ) ?
 
Merci par avance !!!!  :hello:  
 
 
Donc, si j'ai bien tout lu Freud :
 
(*) si je veux faire une fonction générique qui traite des données indépendamment de leur type je peux utiliser, préférablement, deux solutions.  
 
1) Je fait une fonction qui renvoie un void *, qui sera alloué dans la fonction. Par exemple, le prototype serait :
 

Code :
  1. void * ma_fonction(int i, void * data, size_t size, size_t numel, void (*f) (void *, ...) );


 
où la variable i permet de choisir les cas à traiter, data est les données passées en entrée, size la taille du type de data (int, double, etc) et numel le nombre d'élement, numel > 1 si c'est un tableau d'éléments. La fonction renvoie un void *, pointeur vers un bloc mémoire alloué à l'intérieur de la fonction ma_fonction().
 
2) Utiliser une union pour que la fonction renvoie la solution dans cette union. Par exemple, je crée une union :
 

Code :
  1. union mon_union {
  2.    int a;
  3.    double b;
  4.    double ** c;
  5.    //etc ...
  6. };


 
et le prototype de ma fonction générique serait alors :

Code :
  1. void ma_fonction(int i, void * data, size_t size, size_t numel, void (*f) (void *, ...), union mon_union * res );


 
et dans ce cas, à l'intérieur de ma_fonction(), je renvoie le resultat sur le membre de l'union correspondant. Par exemple, si je renvoie un tableau de double, je ferai, à l'intérieur de ma_fonction() :

Code :
  1. double *  resultat = malloc(sizeof(double) * numel);
  2. //on remplit le tableau
  3. *res->c = resultat;


 
(*) Les choses que je ne peut pas faire, sont de renvoyer le résultat dans un void * où même un void **,  car void* n'est pas déréférençable.  
 
Par exemple, si mon prototype de fonction générique est :
 

Code :
  1. void ma_fonction(int i, void * data, size_t size, size_t numel, void * res);


 
ça ne sera pas bon, car si je renvoie une valeur dans le résultat, je serai obligé de faire, à l'intérieur de la fonction :

Code :
  1. *res = 1; //dans l'exemple ou la valeur de résultat est 1


 
Au pire, je pourrais le faire avec un memcpy() dans le cas ou j'ai void **
 
Une autre petite question si c'est possible .. :o :
 
Je ne comprend pas vraiment l'interêt d'utiliser des pointeurs de fonctions, dans une fonction, si au final on a quand même un paramètre qui dit quelle cas on est censé traiter, par exemple, si on a  
 

Code :
  1. void ma_fonction(int cas_a_traiter, void * data, size_t size, size_t numel, void (*f) (void * , void * ) );


 
on fait un swithc dans la fonction pour dire que on traite tel ou tel cas :

Code :
  1. switch(cas_a_traiter) {
  2.        case 1:
  3.                   //on fait les traitement avec la fonction f dont l'adresse est passée en arguement
  4.                   printf("resultat=%d", blabla_i); //par exemple on est dans le cas ou on traite des entiers
  5.        case 2:
  6.                   //on fait les traitement avec la fonction f dont l'adresse est passée en arguement
  7.                   printf("resultat=%f", blabla_f); //par exemple on est dans le cas ou on traite des float
  8. //etc
  9. }


 
Ne serait-ce pas aussi facile de ne pas utiliser de pointeur de fonction et d'appeler une fonction différente dans chacun des cas du case :

Code :
  1. switch(cas_a_traiter) {
  2.        case 1:
  3.                   fonction_qui_traite_des_int(); //on fait les traitement avec la fonction f dont l'adresse est passée en arguement
  4.                   printf("resultat=%d", blabla_i); //par exemple on est dans le cas ou on traite des entiers
  5.        case 2:
  6.                   fonction_qui_traite_des_float(); //on fait les traitement avec la fonction f dont l'adresse est passée en arguement
  7.                   printf("resultat=%f", blabla_f); //par exemple on est dans le cas ou on traite des float
  8. //etc
  9. }


et dans ce cas on a juste  

Code :
  1. void ma_fonction(int cas_a_traiter, void * data, size_t size, size_t numel );


 
 
 
Merci par avance  :hello:  :jap:  :jap:  :jap:  :love:  :love:  :love:  :o

Reply

Marsh Posté le 11-06-2007 à 12:02:35   

Reply

Marsh Posté le 12-06-2007 à 21:05:15    

up ....
 
vraiment personne ?  :cry:

Reply

Marsh Posté le 13-06-2007 à 00:27:04    

bin le C est la généricité :D
ce que tu cherches à faire est plustôt casse-gueule (et lent, car effectivement un moment ou a un autre tu risques d'avoir des switch).
 
suivant ce que tu veux faire, tu peux essayer de passer une structure contenant des pointeurs de fonctions style:
 
struct ops
{
   void (*allocate)(void*);
   void (*init)(void *);
   void (*process)(void *);
   void (*free)(void *);
};
 
avec une approche à la plug-in.
 
menfin le C et la généricité :D

Reply

Marsh Posté le 13-06-2007 à 09:28:51    

Perso, j'utilise aussi une structure de pointeur sur fonction, mais pas de la meme manière
Exemple facile, un interpreteur de commande.
Mon programme recoit un char* alloué, et doit exécuter qqchose en fonction de ce que contient ce char *
Mon programme à une structure qui ressemble à ca :

Code :
  1. typedef struct cmd_s
  2. {
  3.   char *cmd;
  4.   void (*cmd)(char *str);
  5. }                      cmd_t;


 
Je fais un tableau de cette structure

Code :
  1. const cmd_t cmds[] = {
  2.   { "exit", cmd_exit },
  3.   { "status", cmd_status },
  4.    { NULL, NULL }
  5. };


 
Ce qui se passe dans mon code principale :

Code :
  1. int i;
  2. for (i = 0; cmds[i].cmd != NULL; i++)
  3.     if (!strcmp(str, cmds[i].cmd))
  4.       break ;
  5.   if (cmds[i].cmd != NULL) {
  6.     return (cmds[i].fct(str));
  7.   }
  8.   return (0);


 
Voila, je n'ai pas utilisé de void *
Et a chaque fois que je peux apprendre une commande à mon logiciel, je rajoute une ligne dans mon tableau et je n'ai plus qu'a faire la fonction correspondante
 
J'utilise les void * pour des structures de données qui sert de  'conteneur dynamique'. Comme une liste chainé, une table de hach, ...


Message édité par nORKy le 13-06-2007 à 09:32:01
Reply

Sujets relatifs:

Leave a Replay

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