[c] comparaison générique (ou comment comparer des elements du type void * ...)

Soyez le premier à donner votre avis sur cette source.

Snippet vu 7 724 fois - Téléchargée 23 fois

Contenu du snippet

Bon, je sais que c'est pas très clair, mais c'est un peu compliqué à expliquer seulement à l'aide du titre.
Alors voilà mon problème. J'avais codé une liste en C dont les élements à l'interieur était du type void*. Ainsi, la liste pouvait contenir des pointeurs sur n'importe quoi. En clair, la liste pouvait donc contenir n'importe quoi. Mais le soucis, c'est que je devais créer une fonction sort() associée à cette liste pour pouvoir comparer les élements à l'interieur ... Sauf que ces élements sont concidérés dans la liste comme des pointeurs du type void* ... Et donc impossible d'en faire quoi que ce soit.
La solution, c'est d'utiliser un pointeur de fonction sur une fonction de comparaison dont les paramètres sont du type void*, qui retourne un booléen (ou quoi que ce soit qui peut aider à comparer). Ce pointeur est alors utilisé comme paramètre de la fonction sort() dont je vous parlais précedement.
On doit ensuite donner la fonction adaptée aux élements présents dans la liste.
Dans l'exemple que je vous donne, c'est pas une liste, mais une simple fonction qui détermine si ces 2 premiers paramètres sont egaux, à l'aide du 3ème paramètre qui est en fait le pointeur sur la fonction de comparaison.

Source / Exemple :


#include <stdio.h>
#include <stdlib.h>

typedef enum{TRUE = 1, FALSE = 0} tBoolean;

#define and &&

#define tElement void *

typedef struct sComparator *tComparator;
struct sComparator
{
   tBoolean (*areEqual)(tElement, tElement);
};

tComparator Comparator_allocate()
{
   return (tComparator)malloc(sizeof(struct sComparator));
}

typedef struct sInteger *tInteger;
struct sInteger
{
   int Value;
   
   tInteger (*create)(int);
   
   tComparator Comparator;   
};

tInteger Integer_allocate()
{
   return (tInteger)malloc(sizeof(struct sInteger));
}

tInteger Integer_create(int value)
{
   tInteger This = Integer_allocate();
   This -> Value = value;
   return This;   
}

tBoolean Integer_areEqual(tElement a, tElement b)
{
   tInteger i = (tInteger)a;
   tInteger j = (tInteger)b;
   
   return (i -> Value) == (j -> Value);
}

tInteger Integer;

void createIntegerType(void)
{
   Integer = Integer_allocate();
   Integer -> create = Integer_create;
   tComparator comparator = Comparator_allocate();
   comparator -> areEqual = Integer_areEqual;
   Integer -> Comparator = comparator;
}

typedef struct sComplex *tComplex;
struct sComplex
{
   float RealPart;
   float ImaginaryPart;
   
   tComplex (*create)(float, float);
   
   tComparator Comparator;
};

tComplex Complex_allocate()
{
   return (tComplex)malloc(sizeof(struct sComplex));   
}

tComplex Complex_create(float real_part, float imaginary_part)
{
   tComplex This = Complex_allocate();
   This -> RealPart = real_part;
   This -> ImaginaryPart = imaginary_part;
   return This;
}

tBoolean Complex_areEqual(tElement a, tElement b)
{
   tComplex x = (tComplex)a;
   tComplex y = (tComplex)b;
   
   return ((x -> RealPart) == (y -> RealPart)) and ((x -> ImaginaryPart) == (y -> ImaginaryPart));
}

tComplex Complex;

createComplexType()
{
   Complex = Complex_allocate();
   tComparator comparator = Comparator_allocate();
   Complex -> create = Complex_create;
   comparator -> areEqual = Complex_areEqual;
   Complex -> Comparator = comparator;
}

tBoolean areEqual(tElement a, tElement b, tComparator comparator)
{
   return comparator -> areEqual(a, b);
}

int main(void)
{
   createIntegerType();
   createComplexType();
   
   tInteger i = Integer -> create(4);
   tInteger j = Integer -> create(4);
   
   tComplex x = Complex -> create(1, 1);
   tComplex y = Complex -> create(1, 1);
   
   tBoolean b;
   
   b = areEqual(i, j, Integer -> Comparator);
   if(b) printf("Oui ! Ces 2 entiers sont egaux ! \n");
   
   b = areEqual(x, y, Complex -> Comparator);
   if(b) printf("Oui ! Cest 2 complexes sont egaux ! \n");
   
   system("PAUSE");
   return 0;   
}

Conclusion :


J'ai rien trouver sur internet pour faire ce genre de chose et c'est pourquoi je le poste. De plus, j'ai codé de tel manière à ce que ça ressemble à de l'objet. Mais c'est pas le problème ici. En tout cas, le niveau de la source est expert parce que mine de rien, c'est pas mal tendu pour comprendre.

A voir également

Ajouter un commentaire

Commentaires

LocalStone
Messages postés
515
Date d'inscription
mercredi 19 mars 2003
Statut
Membre
Dernière intervention
1 mars 2009

Grrr ... Je sais pas comment vous expliquer.
Je sais qu'il n'y a pas de référence en C. La manière dont le code est structuré permet dans ce cas de SIMULER des références, justement en cachant totalement la notion de pointeur. Naturellement, c'est stupide de faire ça, étant donné qu'il existe le Java, le C++, le C# et j'en passe et des meilleurs. Mais ! ... Bah dans le cadre de mon projet, je devais absolument le faire en C. C'est pour ça que j'ai du faire ça. Voilà voilà ...
cs_vicenzo
Messages postés
179
Date d'inscription
mardi 16 août 2005
Statut
Membre
Dernière intervention
25 août 2010

Bon, LocalStone :

* primo : la notion de "référence" n'existe pas en C ! Donc dire : "je fais du C avec des références" est un non sens. En C il y des objets (au sens générique de variable et non en terme de poo) et des pointeurs sur ces objets !

* L'article que tu mentionnes "le C Objet" explique en fait l'idée qu'a eu un certain Bjarne Soustroup il y a 25 ans quant il a crée le "C with classes" qui est devenu le C++. Au début, le code "C with classes" était présenté à un précompileur qui se chargait de générer un code C dans le même esprit que celui de l'article...

* Si tu a besoin d'aide sur le C, n'hésites pas, demande !!!
LocalStone
Messages postés
515
Date d'inscription
mercredi 19 mars 2003
Statut
Membre
Dernière intervention
1 mars 2009

:) En fait vous n'êtes pas encore prêt ...
Non, je plaisante. C'est vrai que j'ai pas trop expliqué pourquoi le code est un peu bizarre. En fait, j'ai appris le C cette année. Je connaissais déjà le Java, le C# et tout ça, mais je ne connaissais pas le C. Et il se trouve que dans l'école dans laquelle je me trouve, il nous appris à nous servir du C en utilisant que des références. En fait, ils pensaient déjà au semestre suivant : l'apprentissage du Java.
Du coup j'ai cherché et j'ai trouvé ça : http://chgi.developpez.com/c/objet/.
Et en fait, j'ai globalement suivi cette methode. J'ai seulement rajouté l'idée de l'instance porteuse de constructeut avec la variable globale dont le nom est presque identique au type.
Voilà voilà ... Maintenant, je suis d'accord, autant faire du C++. Bah ouais, mais je peux pas ... Pour l'instant :)
Dans l'espoir d'avoir été un peu mieux compris ...
cs_vicenzo
Messages postés
179
Date d'inscription
mardi 16 août 2005
Statut
Membre
Dernière intervention
25 août 2010

simplicité est mère d'efficacité ! Pourquoi faire compliqué quand le problème est tout simple. !

C'est pourquoi, je ne pige pas le choix du niveau initié !

les pointeurs génériques et les pointeurs de fonction ont fait la force (puissance) du C et en même temps sa faiblesse (la + grande source de bug au monde !)

Donc, pour ta fonction sort, utilise qsort() en lui fournissant une fonction de tri de ton choix, tu ne pourra pas faire mieux, je pense !
BruNews
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
16
Oui oui Vicenzo, c'est le type de code qu'on emploie ordinairement avec une fonction comme qsort(), très simple d'écriture et qu'un compilo correct optimisera parfaitement.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.