Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1475 connectés 

  FORUM HardWare.fr
  Programmation
  C

  Question sur les structures

 


 Mot :   Pseudo :  
 
 Page :   1  2
Page Précédente
Auteur Sujet :

Question sur les structures

n°1566281
in_your_ph​ion
Posté le 28-05-2007 à 16:41:13  profilanswer
 

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:

mood
Publicité
Posté le 28-05-2007 à 16:41:13  profilanswer
 

n°1566283
_darkalt3_
Proctopathe
Posté le 28-05-2007 à 16:53:18  profilanswer
 

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
n°1566284
matafan
Posté le 28-05-2007 à 16:54:45  profilanswer
 

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.

n°1566285
_darkalt3_
Proctopathe
Posté le 28-05-2007 à 16:55:37  profilanswer
 

Bon ben j'ai rien dit alors.


---------------
Töp of the plöp
n°1566293
in_your_ph​ion
Posté le 28-05-2007 à 17:17:01  profilanswer
 

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

n°1566296
phosphorel​oaded
Posté le 28-05-2007 à 17:22:38  profilanswer
 

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.

n°1566306
BifaceMcLe​OD
The HighGlandeur
Posté le 28-05-2007 à 17:35:51  profilanswer
 

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)

n°1566310
in_your_ph​ion
Posté le 28-05-2007 à 17:41:12  profilanswer
 

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 :)

n°1566556
nORKy
Grmmph...
Posté le 29-05-2007 à 10:41:09  profilanswer
 

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

n°1566883
Sve@r
Posté le 29-05-2007 à 18:47:26  profilanswer
 

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.
mood
Publicité
Posté le 29-05-2007 à 18:47:26  profilanswer
 

n°1566940
el muchach​o
Comfortably Numb
Posté le 29-05-2007 à 20:50:05  profilanswer
 

_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
n°1566945
matafan
Posté le 29-05-2007 à 20:59:09  profilanswer
 

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.

n°1567368
in_your_ph​ion
Posté le 30-05-2007 à 16:30:54  profilanswer
 

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
n°1567619
matafan
Posté le 31-05-2007 à 08:22:45  profilanswer
 

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.

n°1567659
Trap D
Posté le 31-05-2007 à 09:52:58  profilanswer
 

: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
n°1567731
in_your_ph​ion
Posté le 31-05-2007 à 11:19:00  profilanswer
 

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
n°1567741
Taz
bisounours-codeur
Posté le 31-05-2007 à 11:30:33  profilanswer
 

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

n°1567742
Taz
bisounours-codeur
Posté le 31-05-2007 à 11:30:56  profilanswer
 

fais des macros ...


Message édité par Taz le 31-05-2007 à 11:32:04
n°1567749
in_your_ph​ion
Posté le 31-05-2007 à 11:35:03  profilanswer
 

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
n°1567788
Taz
bisounours-codeur
Posté le 31-05-2007 à 12:13:52  profilanswer
 

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

n°1567804
in_your_ph​ion
Posté le 31-05-2007 à 12:34:30  profilanswer
 

Taz a écrit :

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


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

n°1567807
Taz
bisounours-codeur
Posté le 31-05-2007 à 12:38:20  profilanswer
 

bah corrige les types au lieu de caster

n°1567813
matafan
Posté le 31-05-2007 à 12:43:17  profilanswer
 

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

n°1567823
Trap D
Posté le 31-05-2007 à 12:55:08  profilanswer
 

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
n°1567857
matafan
Posté le 31-05-2007 à 13:20:31  profilanswer
 

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.

n°1567875
in_your_ph​ion
Posté le 31-05-2007 à 13:32:05  profilanswer
 

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
n°1568458
in_your_ph​ion
Posté le 01-06-2007 à 10:54:15  profilanswer
 

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
n°1568559
matafan
Posté le 01-06-2007 à 13:08:39  profilanswer
 

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*)) ;

n°1568627
in_your_ph​ion
Posté le 01-06-2007 à 14:39:20  profilanswer
 

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:

n°1568634
Sve@r
Posté le 01-06-2007 à 14:44:36  profilanswer
 

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.
n°1568637
Taz
bisounours-codeur
Posté le 01-06-2007 à 14:45:09  profilanswer
 

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

n°1568641
in_your_ph​ion
Posté le 01-06-2007 à 14:47:47  profilanswer
 

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 ??

n°1568654
matafan
Posté le 01-06-2007 à 14:59:05  profilanswer
 

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*));

n°1568656
Sve@r
Posté le 01-06-2007 à 14:59:08  profilanswer
 

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.
n°1569873
in_your_ph​ion
Posté le 04-06-2007 à 16:27:40  profilanswer
 

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

n°1569937
Sve@r
Posté le 04-06-2007 à 17:19:24  profilanswer
 

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.
n°1569958
in_your_ph​ion
Posté le 04-06-2007 à 18:12:42  profilanswer
 

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
n°1570010
Sve@r
Posté le 04-06-2007 à 20:53:12  profilanswer
 

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.
n°1570051
in_your_ph​ion
Posté le 04-06-2007 à 23:02:49  profilanswer
 

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
n°1570091
Sve@r
Posté le 05-06-2007 à 07:49:31  profilanswer
 

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.
mood
Publicité
Posté le   profilanswer
 

 Page :   1  2
Page Précédente

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  Question sur les structures

 

Sujets relatifs
question sur les pointeurs de fonctionsquestion sur les pointeurs
Question PHP, PEAR SOAP, Dotnet et sérialisation[J2EE] Question générale
Question sur les listbox vba excelAffectation de structures
[C]Passer un tableau de structures en paramètresQuestion sur les schemas d'une base de données
Question bête sur notepad++Question sur les structures
Plus de sujets relatifs à : Question sur les structures


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR