Question sur les structures

Question sur les structures - C - Programmation

Marsh Posté le 28-05-2007 à 16:41:13    

Bonjour,
 
J'aimerai savoir si quand on déclare une structure, quelle taille de mémoire ça prend ? Est ce que la taille allouée change si on réorganise les champs?
 
merci  :love:  :love:

Reply

Marsh Posté le 28-05-2007 à 16:41:13   

Reply

Marsh Posté le 28-05-2007 à 16:53:18    

1/ Euh il me semble que la taille d'une struct est la taille des champs qui la composent.
 
2/ Donc non.


---------------
Töp of the plöp
Reply

Marsh Posté le 28-05-2007 à 16:54:45    

Ca dépend. Ca dépend du compilateur, de l'architecture de la machine cible, des options de compilation... Et la raison pour laquelle c'est variable, c'est que les compilos ajoutent parfois du padding pour avoir des champs alignés comme il faut.

Reply

Marsh Posté le 28-05-2007 à 16:55:37    

Bon ben j'ai rien dit alors.


---------------
Töp of the plöp
Reply

Marsh Posté le 28-05-2007 à 17:17:01    

donc c'est la taille du plus grand (en mémoire) champ ?

Reply

Marsh Posté le 28-05-2007 à 17:22:38    

Hein? La taille de la plus grande des parties? Tu as compris quelque chose aux structures ou bien ta dernière phrase a une signification qui m'échappe?
 
 
Une structure est au moins aussi grande que la somme des tailles des parties qui la compose, c'est tout ce qu'on peut dire. Certains compilos auront besoin de plus de place, d'autres pas.

Reply

Marsh Posté le 28-05-2007 à 17:35:51    

Ne pas confondre les structs et les unions. Dans une union, tous les champs partagent le même espace. Un seul n'a de sens à un instant donné, et effectivement, la taille de l'union, c'est la taille du plus grand de ses champs.
 
Dans une struct, les champs sont placés les uns à côté des autres. Donc comme dit PhosphoReloaded, la taille de la struct est la somme des tailles des champs qui la composent (plus la taille des espaces vides ajoutés pour aligner chaque champ sur un début de mot machine)

Reply

Marsh Posté le 28-05-2007 à 17:41:12    

BifaceMcLeOD a écrit :

Ne pas confondre les structs et les unions. Dans une union, tous les champs partagent le même espace. Un seul n'a de sens à un instant donné, et effectivement, la taille de l'union, c'est la taille du plus grand de ses champs.
 
Dans une struct, les champs sont placés les uns à côté des autres. Donc comme dit PhosphoReloaded, la taille de la struct est la somme des tailles des champs qui la composent (plus la taille des espaces vides ajoutés pour aligner chaque champ sur un début de mot machine)


 
d'accord. Merci :)

Reply

Marsh Posté le 29-05-2007 à 10:41:09    

Je rejoins ton sujet sur les pointeurs et ton tableau de int.
Pareil ici, si tu fais un tableau nomé T de 5 structure, si tu fais T+1, il te renverra correctement l'adresse de la prochaine structure car il sait quelle taille fait ta structure

Reply

Marsh Posté le 29-05-2007 à 18:47:26    

nORKy a écrit :

Je rejoins ton sujet sur les pointeurs et ton tableau de int.
Pareil ici, si tu fais un tableau nomé T de 5 structure, si tu fais T+1, il te renverra correctement l'adresse de la prochaine structure car il sait quelle taille fait ta structure


Ce qu'on nomme communément "arithmétique des pointeurs"
=> "pt + n" donne comme résultat une adresse égale à "pt + n * sizeof(*pt)"


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

Marsh Posté le 29-05-2007 à 18:47:26   

Reply

Marsh Posté le 29-05-2007 à 20:50:05    

_darkalt3_ a écrit :

1/ Euh il me semble que la taille d'une struct est la taille des champs qui la composent.


Non. Le compilo va organiser la structure de façon à ce que les champs s'alignent sur la taille des mots utilisés par la cible, de façon à optimiser l'accès aux données par pointeur. Cela signifie qu'il va padder pour que la taille de la structure soit un multiple entier du mot mémoire. Cela dépend donc de l'architecture cible.


Message édité par el muchacho le 29-05-2007 à 20:53:52
Reply

Marsh Posté le 29-05-2007 à 20:59:09    

Ca dépend aussi des options de compil comme je l'ai déjà dit. En particulier les compilos ont généralement une option pour "packer" les structures, c'est-à-dire ne pas utiliser de padding. Dans ce cas la taille de la structure et la somme des tailles des membres.

Reply

Marsh Posté le 30-05-2007 à 16:30:54    

nORKy a écrit :

Je rejoins ton sujet sur les pointeurs et ton tableau de int.
Pareil ici, si tu fais un tableau nomé T de 5 structure, si tu fais T+1, il te renverra correctement l'adresse de la prochaine structure car il sait quelle taille fait ta structure

 

Merci. ok, donc, quand on a un tableau T et qu'on se déplace sur les adresses, on a besoin de faire

 
Code :
  1. T + 5
 

et non pas

Code :
  1. T + 5*sizeof(type_de_T)
 

c'est bien cela ?....?

 

j'aimerai savoir si ce que dis ce site est vrai :
http://rperrot.developpez.com/articles/c/genericite/

 

notamment dans la section III :

 
Citation :


Intuitivement, nous pourrions faire ceci :

 

void parcours( void * data , size_t nb_elt , size_t size )
{
 size_t i;
 for( i = 0 ; i < nb_elt ; ++i )
 {
  printf("%p\n", data + (i * size) );
 }
}

 

Mais nous avons vu que le calcul d'adresse ne pouvait pas être effectué sur un pointeur générique, il faut donc passer par un autre pointeur.

 

car ca compile chez moi, et il me semblait que on faisait T+5 et non pas T+5*sizeof(type_de_T) car quand on se déplace sur un adresse, c'est une addresse donc peut importe vers quoi ca pointe c'est la taille d'une case contenant une addresse (4 octets)

 


merci  :jap:

 


Message édité par in_your_phion le 30-05-2007 à 16:31:45
Reply

Marsh Posté le 31-05-2007 à 08:22:45    

Ben oui mais justement, pour un void * on ne sait pas sur quoi il pointe... C'est pour celà qu'on ne peut pas faire d'arithmétique de pointeur sur un void *. On ne peut pas non plus le déréfencer.
 
Par contre une façon correcte d'écrire parcours est (je n'ai pas le temps de tester, donc attention je peux faire une connerie) :

Code :
  1. void parcours( void * data , size_t nb_elt , size_t size )
  2. {
  3.     size_t i;
  4.     for( i = 0 ; i < nb_elt ; ++i )
  5.     {
  6.         printf("%p\n", ((char *)data) + (i * size) );
  7.     }
  8. }


En castant data en char *, tu peux faire de l'arithmétique de pointer dessus. Et par définition sizeof (char *) == 1, donc tu te déplace bien de "size" octets à chaque fois.

Reply

Marsh Posté le 31-05-2007 à 09:52:58    

:non: Faux :  sizeof (char *) == 1,
c'est sizeof char == 1, attention.

Message cité 2 fois
Message édité par Trap D le 31-05-2007 à 09:53:33
Reply

Marsh Posté le 31-05-2007 à 11:19:00    

Trap D a écrit :

:non: Faux :  sizeof (char *) == 1,
c'est sizeof char == 1, attention.

 

ok, merci  :jap:

 

donc, si je résume : pour créer une fonction générique on a besoin d'un prototype dans le genre de :

 
Code :
  1. void * ma_fonction_generique ( void * objet, size_t taille_objet);
 

et si on veut faire des opérations sur les adresses de cet objet, il faut faire un cast en (char*) ? Par exemple si je veux faire une fonction addition générique, je ne peux pas faire:

Code :
  1. void * add_gen(const void * a, const void * b, size_t bsize) {
  2.   void * c = malloc(sizeof(bsize));
  3.   *c = *a + *b;
  4.   return c;
  5. }
 

car void n'est pas déréférencable. Est ce que je pourrai faire un truc du genre :

 
Code :
  1. void * add_gen(int cases, void * a, void *b );
  2. int main() {
  3.   int un = 1;
  4.   int deux = 2;
  5.  
  6.   int c = (int)add_gen(1, &un, &deux );
  7.   printf("c=%d\n",c);
  8.   return 0;
  9. }
  10. void * add_gen(int cases, void * a, void * b ) {
  11.   switch (cases) {
  12.     case 1:
  13.       printf("entiers\n" );
  14.       return (void*)(*(int*)a + *(int*)b);
  15.  
  16. //etc ...avec float, double, ...
  17.      
  18.   }
  19.   return (void*)NULL ;
  20. }
 

mais je sens que c'est crado  :sweat: . Je fais avec les pointeurs de fonctions ????

 

help plz  :whistle:  :cry:  :cry:  :cry:

 


Message édité par in_your_phion le 31-05-2007 à 11:21:22
Reply

Marsh Posté le 31-05-2007 à 11:30:33    

(void*)(*(int*)a + *(int*)b);
 
c'est beau ça, si tu as a->3 et b->5 ça retourne (void*)8 ...

Reply

Marsh Posté le 31-05-2007 à 11:30:56    

fais des macros ...


Message édité par Taz le 31-05-2007 à 11:32:04
Reply

Marsh Posté le 31-05-2007 à 11:35:03    

Taz a écrit :

(void*)(*(int*)a + *(int*)b);

 

c'est beau ça, si tu as a->3 et b->5 ça retourne (void*)8 ...

 

:pt1cable:

 

et si je fais ça, est-ce bien :

 
Code :
  1. void  * add_gen_pf(const void * a, const void *b, void * add_type(const void*,const void*) ) ;
  2. int add_integer(const int * a, const int * b);   
  3. int main() {
  4.   int un = 1;
  5.   int deux = 2;
  6.   void * (*f)(const void*, const void*) = (void*)&add_integer;
  7.  
  8.   int c = (int)add_gen_pf(&un,&deux, f) ;
  9.   printf("c=%d\n",c);
  10.   return 0;
  11. }                               
  12. void  * add_gen_pf(const void * a, const void *b, void * add_type(const void*,const void*) ) {
  13.   void * res = add_type(a,b);
  14.   return res;
  15. }
  16. int add_integer(const int * a, const int * b) {
  17.   return (*a + *b);
  18. }
 

[:tageueuil]

 

comment ça marche avec les macros ???

 


Message édité par in_your_phion le 31-05-2007 à 11:37:04
Reply

Marsh Posté le 31-05-2007 à 12:13:52    

(void*)&add_integer pourquoi tu fais ça ...

Reply

Marsh Posté le 31-05-2007 à 12:34:30    

Taz a écrit :

(void*)&add_integer pourquoi tu fais ça ...


 
sionon j'ai le message :
warning: initialization from incompatible pointer type

Reply

Marsh Posté le 31-05-2007 à 12:38:20    

bah corrige les types au lieu de caster

Reply

Marsh Posté le 31-05-2007 à 12:43:17    

Trap D a écrit :

:non: Faux :  sizeof (char *) == 1,
c'est sizeof char == 1, attention.


Oui bien sûr, je voulais dire "sizeof (char) == 1". D'ailleurs c'est pas non plus "sizeof char == 1" puisqu'avec sizeof un type doit être parenthèses :D

Reply

Marsh Posté le 31-05-2007 à 12:55:08    

Citation :

D'ailleurs c'est pas non plus "sizeof char == 1" puisqu'avec sizeof un type doit être parenthèses :D


Ben non puisqu'en C sizeof est un opérateur pas une fonction


Message édité par Trap D le 31-05-2007 à 12:55:51
Reply

Marsh Posté le 31-05-2007 à 13:20:31    

while aussi c'est operateur, pourtant il demande des parenthèses... Avec sizeof, un nom de variable ne nécessite pas de parenthèses. Un type nécessite des parenthèses. Bref c'est "sizeof a", et "sizeof (char)". "sizeof char" ne compile pas.

Reply

Marsh Posté le 31-05-2007 à 13:32:05    

Taz a écrit :

bah corrige les types au lieu de caster

 

comme ca alors ?????????????????????

 
Code :
  1. void  * add_gen_pf(const void * a, const void *b, void * add_type(const void*,const void*) ) ;
  2. int add_integer(const int * a, const int * b);
  3. int main() {
  4.   int un = 1;
  5.   int deux = 2;
  6.   int (*f)(const int*, const int*) = &add_integer;
  7.  
  8.   int c = (int)add_gen_pf(&un,&deux, (void*)f) ;
  9.   printf("c=%d\n",c);
  10.   return 0;
  11. }
  12. int add_integer(const int * a, const int * b) {
  13.   return (*a + *b);
  14. }
 

merci pour le feedback sur la conception, quel est le mieux ?  :jap:

Message cité 1 fois
Message édité par in_your_phion le 31-05-2007 à 13:32:26
Reply

Marsh Posté le 01-06-2007 à 10:54:15    

up ......

 

quelqu'un pourrait t-il me dire qu'elle est la meilleure solution parmi les bout de code avec les pointeurs de fonctions ? Je ne sais pas a quel niveau faire les casts ...

 

merci par avance  :jap:


Message édité par in_your_phion le 01-06-2007 à 10:54:27
Reply

Marsh Posté le 01-06-2007 à 13:08:39    

C'est quoi ce pointeur casté en int (c) ?
 
Le 3ème argument de add_gen_pf() est sensé être un pointeur de fonction ? Dans ce cas ta déclaration est mauvaise. Il faut :

Code :
  1. void  * add_gen_pf(const void * a, const void *b, void (*add_type)(const void*,const void*)) ;

Reply

Marsh Posté le 01-06-2007 à 14:39:20    

matafan a écrit :

C'est quoi ce pointeur casté en int (c) ?
 
Le 3ème argument de add_gen_pf() est sensé être un pointeur de fonction ? Dans ce cas ta déclaration est mauvaise. Il faut :

Code :
  1. void  * add_gen_pf(const void * a, const void *b, void (*add_type)(const void*,const void*)) ;



 
 mais je croyais que void c'est rien ? raaaaaa, je comprend plus rien  :cry:  :cry:

Reply

Marsh Posté le 01-06-2007 à 14:44:36    

in_your_phion a écrit :

mais je croyais que void c'est rien ? raaaaaa, je comprend plus rien  :cry:  :cry:


Tu confonds le type "void" (appliqué uniquement aux fonctions et qui permet d'indiquer qu'une fonction ne renverra rien) et "void étoile" signifiant "pointeur universel". Les deux ne sont pas la même chose.
 
C'est un peu comme si tu confondais "double" (variable de 64 bits permettant de stocker une valeur en virgule flottante) et "double étoile" (variable de 16 ou 32 bits (ça dépend de l'architecture et on peut même en avoir 64) permettant de stocker l'adresse d'une variable de type "double" )
 
Donc un pointeur universel (de type "void étoile" ) est un pointeur pouvant stocker l'adresse de n'importe quelle variable ou fonction. Les concepteurs ont réutilisé le mot "void" car c'était plus pratique que d'en inventer un nouveau...


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

Marsh Posté le 01-06-2007 à 14:45:09    

et ta méthode ne marche pas si sizeof(type) > sizeof(void*). Utilise un argument supplémentaire pour le stockage du résultat

Reply

Marsh Posté le 01-06-2007 à 14:47:47    

Sve@r a écrit :

Tu confonds le type "void" (appliqué uniquement aux fonctions et qui permet d'indiquer qu'une fonction ne renverra rien) et "void étoile" signifiant "pointeur universel". Les deux ne sont pas la même chose.
 
C'est un peu comme si tu confondais "double" (variable de 64 bits permettant de stocker une valeur en virgule flottante) et "double étoile" (variable de 16 ou 32 bits (ça dépend de l'architecture et on peut même en avoir 64) permettant de stocker l'adresse d'une variable de type "double" )
 
Donc un pointeur universel (de type "void étoile" ) est un pointeur pouvant stocker l'adresse de n'importe quelle variable ou fonction. Les concepteurs ont réutilisé le mot "void" car c'était plus pratique que d'en inventer un nouveau...


 
d'accord, merci pour ta réponse .... Mais alors - car il y a toujours un mais  :lol: - comment je pourrais faire avec ma fonction générique qui renvoie un type générale, un double un float ou un canard ? Est ce que ma premier solution est bonne alors ??

Reply

Marsh Posté le 01-06-2007 à 14:59:05    

Au fait, fais gaffe : tout à l'heure j'ai supposé que ta fonction add_type ne renvoyait rien, Si elle doit renvoyer un void *, alors ça devient :

Code :
  1. void  * add_gen_pf(const void * a, const void *b, void *(*add_type)(const void*,const void*));

Reply

Marsh Posté le 01-06-2007 à 14:59:08    

in_your_phion a écrit :

d'accord, merci pour ta réponse .... Mais alors - car il y a toujours un mais  :lol: - comment je pourrais faire avec ma fonction générique qui renvoie un type générale, un double un float ou un canard ? Est ce que ma premier solution est bonne alors ??


J'ai pas bien regardé mais une fonction ne peut renvoyer qu'un seul truc
Si ce truc est un truc simple (char, short, long , double, etc) alors ta fonction est de ce type.
 
Si ce truc est plus complexe (structure, tableau) alors ta fonction doit être de type "pointeur sur structure" ou "pointeur sur type du tableau" car sinon, ce serait trop lourd (t'imagines une structure de 300ko intégralement recopiée lors du return  ? => vaut mieux copier une adresse de 4 octets que 300 => plus rapide).
Bien évidemment, il ne faut pas que ta fonction renvoie un pointeur sur une zone déclarée en "auto" car la zone disparait avec la fin de fonction et tu récupères un pointeur sur que dalle. Donc dans ce cas là, ta fonction n'a que 3 options

  • elle renvoie un pointeur sur une zone static (avec les dangers que cela suppose dans le cas des appels concurrents)
  • elle renvoie un pointeur sur une zone allouée => faudra ensuite penser à libérer a zone
  • elle a reçu en paramètre un pointeur sur la zone à remplir, l'a remplie et renvoie le même pointeur sur la zone pour indiquer "ok"


Dans 99% des cas, le truc à renvoyer est connu à l'avance donc la fonction renvoie un pointeur de type "truc *". Mais il peut arriver que ta fonction doive renvoyer un pointeur sur un truc qui n'est pas connu à l'avance. dans ce cas, elle renvoie un pointeur universel "void *".

Message cité 1 fois
Message édité par Sve@r le 01-06-2007 à 15:00:36

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

Marsh Posté le 04-06-2007 à 16:27:40    

Sve@r a écrit :

J'ai pas bien regardé mais une fonction ne peut renvoyer qu'un seul truc
Si ce truc est un truc simple (char, short, long , double, etc) alors ta fonction est de ce type.
 
Si ce truc est plus complexe (structure, tableau) alors ta fonction doit être de type "pointeur sur structure" ou "pointeur sur type du tableau" car sinon, ce serait trop lourd (t'imagines une structure de 300ko intégralement recopiée lors du return  ? => vaut mieux copier une adresse de 4 octets que 300 => plus rapide).
Bien évidemment, il ne faut pas que ta fonction renvoie un pointeur sur une zone déclarée en "auto" car la zone disparait avec la fin de fonction et tu récupères un pointeur sur que dalle. Donc dans ce cas là, ta fonction n'a que 3 options

  • elle renvoie un pointeur sur une zone static (avec les dangers que cela suppose dans le cas des appels concurrents)
  • elle renvoie un pointeur sur une zone allouée => faudra ensuite penser à libérer a zone
  • elle a reçu en paramètre un pointeur sur la zone à remplir, l'a remplie et renvoie le même pointeur sur la zone pour indiquer "ok"


Dans 99% des cas, le truc à renvoyer est connu à l'avance donc la fonction renvoie un pointeur de type "truc *". Mais il peut arriver que ta fonction doive renvoyer un pointeur sur un truc qui n'est pas connu à l'avance. dans ce cas, elle renvoie un pointeur universel "void *".


 
Ok, merci beaucoup pour ta réponse. Dans la dernière phrase, tu dis que si on ne sait pas ce que renvoi la fonction, alors on lui fait renvoyer un type "void *". C'est la que j'ai un léger problème, car si c'est une valeur que l'on renvoie ? comme dans mon exemple ou la fonction peut renvoyer un int, un double ou un float ..... Dans ce cas comment fait on ?
 
 
merci encore

Reply

Marsh Posté le 04-06-2007 à 17:19:24    

in_your_phion a écrit :

Ok, merci beaucoup pour ta réponse. Dans la dernière phrase, tu dis que si on ne sait pas ce que renvoi la fonction, alors on lui fait renvoyer un type "void *". C'est la que j'ai un léger problème, car si c'est une valeur que l'on renvoie ? comme dans mon exemple ou la fonction peut renvoyer un int, un double ou un float ..... Dans ce cas comment fait on ?
 
 
merci encore


 
Impossible. Une fonction ne peut renvoyer qu'un truc et si ce truc est simple, il ne peut pas être polymorphe.
La seule façon de ruser consiste à travailler avec une union. Une union est comme une structure sauf que tous les champs occupent la même place mémoire donc à un instant donné, un seul champ est utilisable.
Donc tu utilises ton union comme une structure (voir mon post précédent). Ensuite, ta fonction, selon le cas, var remplir tel ou tel champ de l'union que l'appelant récupère ensuite...


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

Marsh Posté le 04-06-2007 à 18:12:42    

Sve@r a écrit :

Impossible. Une fonction ne peut renvoyer qu'un truc et si ce truc est simple, il ne peut pas être polymorphe.
La seule façon de ruser consiste à travailler avec une union. Une union est comme une structure sauf que tous les champs occupent la même place mémoire donc à un instant donné, un seul champ est utilisable.
Donc tu utilises ton union comme une structure (voir mon post précédent). Ensuite, ta fonction, selon le cas, var remplir tel ou tel champ de l'union que l'appelant récupère ensuite...

 


Merci !!

 

Pour répondre à ta question sur les unions, est-ce alors le moyen ? Par exemple avec une fonction qui fait une division générique :

 
Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. union Ures {
  5.   double d_res;
  6.   int i_res;
  7. };
  8. void affiche_division (void * a, void * b, void (*f) (const void *, const void *, union Ures *)   ) ;
  9. void division_int (const void *a, const void * b, union Ures * resultat) ;
  10. void division_double (const void *a, const void * b, union Ures * resultat) ;
  11. int main () {
  12.   double d_un = 3.;
  13.   double d_deux = 2.;
  14.  
  15.   void (*f) (const void *, const void * , union Ures* ) =  &division_double;
  16.   affiche_division( &d_un, &d_deux, f  );
  17. return 0;
  18. }
  19. void affiche_division (void * a, void * b, void (*f) (const void *, const void *, union Ures * )   )  {
  20.   union Ures RES;
  21.   f(a,b,&RES);
  22.   printf("Le résultat est = %f\n",RES.d_res);
  23. }
  24. void division_int  (const void *a, const void * b, union Ures * resultat) {
  25.   const int * A = (int*)a;
  26.   const int * B = (int*)b;
  27.   resultat->i_res =  *A/ *B;
  28. }
  29. void division_double (const void *a, const void * b, union Ures * resultat)  {
  30.   const double * A = (const double *)a;
  31.   const double * B = (const double *)b;
  32.   resultat->d_res =  *A / *B;
  33. }
 

merki bien par avance, je ne vois pas comment faire autrement :/

Message cité 1 fois
Message édité par in_your_phion le 04-06-2007 à 18:17:31
Reply

Marsh Posté le 04-06-2007 à 20:53:12    

in_your_phion a écrit :

Merci !!
 
Pour répondre à ta question sur les unions, est-ce alors le moyen ? Par exemple avec une fonction qui fait une division générique :
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. union Ures {
  5.   double d_res;
  6.   int i_res;
  7. };
  8. void affiche_division (void * a, void * b, void (*f) (const void *, const void *, union Ures *)   ) ;
  9. void division_int (const void *a, const void * b, union Ures * resultat) ;
  10. void division_double (const void *a, const void * b, union Ures * resultat) ;
  11. int main () {
  12.   double d_un = 3.;
  13.   double d_deux = 2.;
  14.  
  15.   void (*f) (const void *, const void * , union Ures* ) =  &division_double;
  16.   affiche_division( &d_un, &d_deux, f  );
  17. return 0;
  18. }
  19. void affiche_division (void * a, void * b, void (*f) (const void *, const void *, union Ures * )   )  {
  20.   union Ures RES;
  21.   f(a,b,&RES);
  22.   printf("Le résultat est = %f\n",RES.d_res);
  23. }
  24. void division_int  (const void *a, const void * b, union Ures * resultat) {
  25.   const int * A = (int*)a;
  26.   const int * B = (int*)b;
  27.   resultat->i_res =  *A/ *B;
  28. }
  29. void division_double (const void *a, const void * b, union Ures * resultat)  {
  30.   const double * A = (const double *)a;
  31.   const double * B = (const double *)b;
  32.   resultat->d_res =  *A / *B;
  33. }



Ben voilà. C'est un joli exercice de style sur les fonctions universelles. Reste le problème de la fonction "affiche_division". Dans ton test, tu lui fais diviser deux doubles donc elle appelle "division_double" et affiche le résultat avec "%f". Mais si elle devait diviser 2 int, il faudrait qu'elle appelle "division_int" et afficher le résultat avec "%d". Donc il te faut un paramètre en plus que tu passes depuis le main et qui indique si tu travailles avec des double ou des int...
 
[edit] Pas la peine de mettre "&" pour récupérer l'adresse d'une fonction => son nom est déjà son adresse

Message cité 1 fois
Message édité par Sve@r le 05-06-2007 à 07:36:03

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

Marsh Posté le 04-06-2007 à 23:02:49    

Sve@r a écrit :

Ben voilà. C'est un joli exercice de style sur les fonctions universelles. Reste le problème de la fonction "affiche_division". Dans ton test, tu lui fais diviser deux doubles donc elle appelle "division_double" et affiche le résultat avec "%f". Mais si elle devait diviser 2 int, il faudrait qu'elle appelle "division_int" et afficher le résultat avec "%d". Donc il te faut un paramètre en plus que tu passes depuis le main et qui indique si tu travailles avec des double ou des int...

 

ok, je crois que je vois. J'avais fait un exemple "un peu bato" pour me permettre de comprendre. Pour les trois cas que tu cites :

 
Citation :


ta fonction n'a que 3 options

 

   * elle renvoie un pointeur sur une zone static (avec les dangers que cela suppose dans le cas des appels concurrents)
    * elle renvoie un pointeur sur une zone allouée => faudra ensuite penser à libérer a zone
    * elle a reçu en paramètre un pointeur sur la zone à remplir, l'a remplie et renvoie le même pointeur sur la zone pour indiquer "ok"

 

je crois que je comprend avec les pointeurs sur une zone allouée :

 
Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. void affiche_division (void * a, void * b, void * (*f) (const void *, const void *)   ) ;
  5. void * division_int (const void *a, const void * b) ;
  6. void * division_double (const void *a, const void * b) ;
  7. int main () {
  8.   double d_un = 3.;
  9.   double d_deux = 2.;
  10.   void * (*f) (const void *, const void *) =  &division_double;
  11.   affiche_division( &d_un, &d_deux, f );
  12.   //system("pause" );
  13. return 0;
  14. }
  15. void affiche_division (void * a, void * b, void * (*f) (const void *, const void *)   )  {
  16.   double * RES = f(a,b);
  17.   printf("Le résultat est = %f\n",*RES);
  18. }
  19. void * division_int (const void *a, const void * b) {
  20.   const int * A = (int*)a;
  21.   const int * B = (int*)b;
  22.   int * resultat = malloc( sizeof( int ) );
  23.   *resultat =  *A/ *B;
  24.   return resultat;
  25. }
  26. void * division_double (const void *a, const void * b)  {
  27.   const double * A = (const double *)a;
  28.   const double * B = (const double *)b;
  29.   double * resultat = malloc( sizeof( double) );
  30.   *resultat =  *A / *B;
  31.   return resultat;
  32. }
 

Mais comment faire avec une zone static (cas numéro un) ? Y'a til une de ces solutions qui est mieux d'un point de vue théorique ou pratique ??

 

merci beaucoup encore  :jap:  :jap:

Message cité 1 fois
Message édité par in_your_phion le 04-06-2007 à 23:06:06
Reply

Marsh Posté le 05-06-2007 à 07:49:31    

in_your_phion a écrit :

ok, je crois que je vois. J'avais fait un exemple "un peu bato" pour me permettre de comprendre. Pour les trois cas que tu cites :
 
 
 
je crois que je comprend avec les pointeurs sur une zone allouée :
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. void affiche_division (void * a, void * b, void * (*f) (const void *, const void *)   ) ;
  5. void * division_int (const void *a, const void * b) ;
  6. void * division_double (const void *a, const void * b) ;
  7. int main () {
  8.   double d_un = 3.;
  9.   double d_deux = 2.;
  10.   void * (*f) (const void *, const void *) =  &division_double;
  11.   affiche_division( &d_un, &d_deux, f );
  12.   //system("pause" );
  13. return 0;
  14. }
  15. void affiche_division (void * a, void * b, void * (*f) (const void *, const void *)   )  {
  16.   double * RES = f(a,b);
  17.   printf("Le résultat est = %f\n",*RES);
  18. }
  19. void * division_int (const void *a, const void * b) {
  20.   const int * A = (int*)a;
  21.   const int * B = (int*)b;
  22.   int * resultat = malloc( sizeof( int ) );
  23.   *resultat =  *A/ *B;
  24.   return resultat;
  25. }
  26. void * division_double (const void *a, const void * b)  {
  27.   const double * A = (const double *)a;
  28.   const double * B = (const double *)b;
  29.   double * resultat = malloc( sizeof( double) );
  30.   *resultat =  *A / *B;
  31.   return resultat;
  32. }


 
Mais comment faire avec une zone static (cas numéro un) ? Y'a til une de ces solutions qui est mieux d'un point de vue théorique ou pratique ??
 
merci beaucoup encore  :jap:  :jap:


 
Ok pour tes malloc. Mais faut aussi les libérer ensuite dans "affiche_division" => free(RES)    (évite les noms en majuscules, on pourrait les confondre avec des macros)
 
Avec une zone static c'est comme ça

Code :
  1. void * division_double (const void *a, const void * b)  {
  2.   static double resultat;
  3.   const double * A = (const double *)a;
  4.   const double * B = (const double *)b;
  5.   resultat =  *A / *B;
  6.   return &resultat;
  7. }


Idem pour "division_int" sinon le reste ne change pas sauf que t'as absolument pas besoin de cette variable "f" dans ton main => affiche_division( &d_un, &d_deux, division_double );
 
Maintenant, d'un point de vue pratique, avoir une zone statique c'est très dangereux. J'ai voulu une fois découper une ligne construite ainsi
info1 info2 x:y:z info3
J'ai donc initialisé une boucle à coup de strtok pour découper chaque info sur la tabulation. Puis j'ai initialisé une seconde boucle à coup de strtok pour découper le x:y:z sur le ":" et c'est complètement parti en torche. A la sortie de la 2° boucle, le pointeur interne de strtok (il n'y en a qu'un seul) était totalement à l'ouest et ne m'a jamais trouvé "info3".
 
D'ailleurs, si tu veux avoir un exemple concret du problème du static, utilise ma fonction donnée en exemple et essaye ceci :

Code :
  1. double val1=7.0;
  2. double val2=3.0;
  3. double val3=10.0;
  4. double val4=4.0;
  5. double *res1=(double*)division_double(&val1, &val2);
  6. double *res2=(double*)division_double(&val3, &val4);
  7. printf("res1=%f, res2=%f\n", *res1, *res2);      // Merci à Matafan pour avoir vu cette erreur


Mais d'abord, essaye d'imaginer quel sera ton résultat avant de tester et de regarder la réalité...

Message cité 1 fois
Message édité par Sve@r le 05-06-2007 à 17:43:17

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

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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