Après "Pimp My Ride" ....."Cast my struct" !!

Après "Pimp My Ride" ....."Cast my struct" !! - C - Programmation

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

Salut,

 

Alors voila, il était une fois ....

 

......et ceci amenant cela, je fus rapidement confronté a un problème de programmation en C.

 

...

 

Donc, je ne comprend pas comment marche les casts sur les structures. J'ai vu un exemple sur le net de programmation générique, ou la personne recherche à passer une structure générique à une fonction, pour une application client-serveur á développer contenant une centaine de formats de trames différentes.

 

http://www.developpez.net/forums/s [...] p?t=345137

 


Je met  le code ici pour que ce soit plus clair :

 
Code :
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. typedef struct Frame { 
  5. void (*send_data)();
  6. } Frame_s; 
  7. typedef struct GenericFrame { 
  8. Frame_s frame;
  9. } GenericFrame_s; 
  10. typedef struct FrameA { 
  11. Frame_s frame;
  12. int n;
  13. } FrameA_s;
  14. typedef struct FrameB {
  15. Frame_s frame;
  16. char str[20];
  17. } FrameB_s; 
  18. typedef struct FrameC {
  19. Frame_s frame;
  20. double f;
  21. } FrameC_s;
  22. void sendDataFrameA(FrameA_s * frame) { 
  23. printf("I send the frame A with n=%d\n", frame->n);
  24. }
  25. void sendDataFrameB(FrameB_s * frame) {
  26.   printf("I send the frame B with string:%s\n", frame->str);
  27. }
  28. void sendDataFrameC(FrameC_s * frame) { 
  29.   printf("I send the frame C with f=%lf\n", frame->f);
  30. }
  31. int main(void) {
  32. GenericFrame_s * frames[3];
  33.   FrameA_s * fA = NULL;
  34.   FrameB_s * fB = NULL; 
  35.   FrameC_s * fC = NULL;
  36.   int i; 
  37.   /* TODO : Verifier allocations*/ 
  38.   fA = malloc(sizeof(*fA));
  39.   fB = malloc(sizeof(*fA));
  40.   fC = malloc(sizeof(*fA)); 
  41.   fA->frame.send_data = sendDataFrameA;
  42.   fA->n = 51; 
  43.   fB->frame.send_data = sendDataFrameB;
  44.   strcpy(fB->str, "hello" );
  45.    fC->frame.send_data = sendDataFrameC;
  46.    fC->f = 13.2; 
  47.   frames[0] = (GenericFrame_s*)fA;
  48.   frames[1] = (GenericFrame_s*)fB;
  49.   frames[2] = (GenericFrame_s*)fC;
  50.   for(i=0; i<3; ++i) {
  51.        frames[i]->frame.send_data(frames[i]);
  52.   } 
  53.  
  54.   free(fA);
  55.   free(fB);
  56.   free(fC);
  57.   return 0;
  58. }
 


Je comprend ce que fais le programme mais pas vraiment le concept, notamment les casts :

Code :
  1. frames[0] = (GenericFrame_s*)fA;
  2.   frames[1] = (GenericFrame_s*)fB;
  3.   frames[2] = (GenericFrame_s*)fC;
 

alors que les structures ne sont pas les mêmes. Quelqu'un pourrait-il m'expliquer comment marches les cast avec des structures, est ce risqué ou est ce normal ??? Est ce que cette démarche est valide.

 

Je ne comprend pas bien non plus le :

Code :
  1. frames[i]->frame.send_data(frames[i]);
 

on envoi a la structure sa structure ?

 

merci par avance  :jap:

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

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

Reply

Marsh Posté le 04-06-2007 à 17:12:34    

in_your_phion a écrit :

alors que les structures ne sont pas les mêmes. Quelqu'un pourrait-il m'expliquer comment marches les cast avec des structures, est ce risqué ou est ce normal ??? Est ce que cette démarche est valide.


 
C'est pas la structure qui est castée, c'est le pointeur. Et si je dis pas de connerie, un pointeur est toujours un pointeur, quelque soit l'élément sur lequel il pointe (tu verras souvent des fonctions prendre en paramètre un void *).
 

in_your_phion a écrit :

on envoi a la structure sa structure ?


 
Oui parceque le C n'est pas un langage objet et que le mot clef "this" n'existe pas. Alors il faut bien passer le contexte en paramètre...
 
 


---------------
When it's from Finland it's good.  - Mon blog
Reply

Marsh Posté le 04-06-2007 à 17:38:07    

Ce genre de chose est en effet risqué vu qu'avec un cast, on bypasse la vérification du typage par le compilo, il faut donc bien calculer son coup et être sûr que les données reçues seront à tous les coups couvertes par l'un des cas prévus, sinon, on arrive rapidement à un crash.
Souvent, dans ce genre de cas, on essaye de faire une union, qui permet une vérification statique. Mais ça reste tout de même rare, parce que c'est plutôt crade, c'est effectivement utile quand on essaye de minimiser les données à transmettre ou sauvegarder (mais dans ce cas, je choisirais un algo de compression plutôt qu'un hack à base cast/union/void *). Et dans l'exemple ci-dessus, ça me parait assez extrême.

Message cité 1 fois
Message édité par el muchacho le 04-06-2007 à 17:41:09
Reply

Marsh Posté le 04-06-2007 à 17:56:31    

el muchacho a écrit :

Et dans l'exemple ci-dessus, ça me parait assez extrême.


 
Ca c'est clair, l'exemple ci-dessus c'est comment essayer de faire de l'objet en C (y'a même une vague notion d'héritage)...


---------------
When it's from Finland it's good.  - Mon blog
Reply

Marsh Posté le 04-06-2007 à 18:17:13    

Code :
  1. typedef struct FrameA {  
  2.   Frame_s frame;
  3.   int n;
  4. } FrameA_s;


Comme tu peut le voir, ta structure FrameA a comme premier membre une structure Frame_s.
 
Si tu as

Code :
  1. FrameA* un_pointeur = &FrameA_s;


ton pointeur pointe vers le début de la structure FrameA_s, c'est à dire qu'il pointe sur son premier membre, si tu caste ton pointeur avec le type du premier membre, tu accèdera correctement à ce premier membre :

Code :
  1. Frame_s* un_autre_pointeur = (Frame_s*)un_pointeur;
  2. // C'est pareil que :
  3. Frame_s* un_autre_pointeur = &(un_pointeur->frame);


Fait un dessin avec des boiboites, tu verra que c'est logique.


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
Reply

Sujets relatifs:

Leave a Replay

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