Probleme de taille de structure avec char[] et double

Probleme de taille de structure avec char[] et double - C - Programmation

Marsh Posté le 24-03-2006 à 15:17:30    

Bonjour,
 
J'ai un probleme bizarre,
 
si je declare :  

Code :
  1. struct cc{
  2.   char c[10];
  3.   double d;
  4. };


==>sizeof = 20, or je devrais avoir 18
 
si je fais :

Code :
  1. struct cc{
  2.   char c[10];
  3.   char d;
  4. };


==>sizeof = 11, ce qui est  cohérent
 

Code :
  1. struct cc{
  2.   double c;
  3.   double d;
  4. };


==>sizeof = 16, cohérent aussi
 
Le problème se pose donc si je met dans ma structure un char[] et un double ou un int.
 
J'aimerais donc savoir d'où viennent ces 2 octets en trop car cela posent des problèmes lorsque je veux transferer ma structure via une socket.
 
 
Merci d'avance.
 

Reply

Marsh Posté le 24-03-2006 à 15:17:30   

Reply

Marsh Posté le 24-03-2006 à 15:18:42    

Problème de l'alignement des données 1,2,4,8 bytes.
Ce règle avec les options pragma pack, voir ton compilo.

Reply

Marsh Posté le 24-03-2006 à 15:21:15    

y a du padding insérer par ton compilateur. soit pour un accès plus rapide, soit par obligation d'alignement. donc si tu forces ton compilateur à ne pas le faire (pragma ou attribut), sois bien sur de ton coup.

Reply

Marsh Posté le 24-03-2006 à 15:25:01    

il est aussi possible de compacter la structure dans un tableau de char si tu en as besoin

Reply

Marsh Posté le 24-03-2006 à 15:52:17    

???

Reply

Marsh Posté le 24-03-2006 à 16:00:00    

si tu veux une image mémoire de ta structure dans laquel tu es sur que tout les champs sont contigues
ou inversement si tu veux lire une structure depuis une source externe (fichier) ou elle est compactée
 
ca evite de forcer l'alignement à la compilation (qui peux nuire aux performance) tout en gardant la possibilité de manipuler une version sans padding

Reply

Marsh Posté le 24-03-2006 à 17:55:15    

skelter a écrit :

si tu veux une image mémoire de ta structure dans laquel tu es sur que tout les champs sont contigues[quotemsg] donc pas une image mémoire :)
 
[quotemsg=1331834,6,88500]
ou inversement si tu veux lire une structure depuis une source externe (fichier) ou elle est compactée


 
bonjour la portabilité
 

skelter a écrit :


ca evite de forcer l'alignement à la compilation (qui peux nuire aux performance) tout en gardant la possibilité de manipuler une version sans padding

va-t-en surtout mal aligné un double sur sparc

Reply

Marsh Posté le 24-03-2006 à 18:04:44    

Taz a écrit :

bonjour la portabilité
 
va-t-en surtout mal aligné un double sur sparc


Justement le mapping 'tableau de unsigned char' est garanti d'être portable. Ensuite on a une structure interne qui fait ce qu'elle peut et on recopie les champs 'à main' byte par byte en faisant les assemblages nécessaires à coup de | et de <<.
 
C'est sans doute pas rapide, mais c'est portable. Il suffit de fixer le format externe une fois pour toutes.

Message cité 2 fois
Message édité par Emmanuel Delahaye le 24-03-2006 à 19:02:16

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 24-03-2006 à 18:51:53    

Emmanuel Delahaye a écrit :

Justement le mapping 'tableau de unsigned char' est garanti d'être portable. Ensuite on a une structure interne qui fait ce qu'elle peut et on recopie les champs 'à main' byte par byte en faisant les assemblages nécessaires à coup de | et de <<.
 
C'est sans doute pas rapide, mais c'est portable. Il suffit de fixer le format externe un fois pour toutes.


 
Il existe en php la fonction "serialize()" qui descend un objet dans une chaîne.
Ca y ressemble beaucoup non ?


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

Marsh Posté le 24-03-2006 à 20:16:13    

> Il existe en php la fonction "serialize()" qui descend un objet dans une chaîne.
Ca y ressemble beaucoup non ?  
 
pas tout à fait... ici il s agit de traiter un double en chaîne binaire. serialize() convertit vraiment en chaîne de caractères.

Reply

Marsh Posté le 24-03-2006 à 20:16:13   

Reply

Marsh Posté le 24-03-2006 à 20:43:55    

Emmanuel Delahaye a écrit :

Justement le mapping 'tableau de unsigned char' est garanti d'être portable. Ensuite on a une structure interne qui fait ce qu'elle peut et on recopie les champs 'à main' byte par byte en faisant les assemblages nécessaires à coup de | et de <<.
 
C'est sans doute pas rapide, mais c'est portable. Il suffit de fixer le format externe une fois pour toutes.


 
absolument, en fait l'erreur par rapport à ce que sous entend Taz serait de traité naivement chaque champ à coup d'affectation ou de memcpy, l'interpretation ne serait pas la meme suivant l'endianess

Reply

Marsh Posté le 24-03-2006 à 22:27:56    

justement, le mapping dans un tableau ne m'est pas possible (c'est pour un TP et le prof veut absolument qu'on envoie la structure sur le socket pour voir les problemes d'endianess (communication entre x86 et SPARC))
 
je vais donc regarder du coté de pragma pack.
 

Reply

Marsh Posté le 24-03-2006 à 22:43:59    

bon ça marche avec  
 

Code :
  1. #pragma pack(push,1)
  2. struct s{
  3. ...
  4. };
  5. #pragma pack(pop)


 
par contre sur solaris gcc me balance un warning "pragma([push],[id],n) is not supported on this target", m'enfin bon ça marche c'est le principal.
 
Merci de votre aide


Message édité par ArthurDent le 24-03-2006 à 22:54:51
Reply

Marsh Posté le 24-03-2006 à 23:00:15    

pourquoi tu veux faire ça en fait ?

Reply

Marsh Posté le 25-03-2006 à 09:55:31    

ArthurDent a écrit :

justement, le mapping dans un tableau ne m'est pas possible (c'est pour un TP et le prof veut absolument qu'on envoie la structure sur le socket pour voir les problemes d'endianess (communication entre x86 et SPARC))


 
Pas besoin d'une structure pour ça. Tu écris "short i=5", tu balances "i" sur ta socket et tu regardes ton nombre à l'arrivée. Normallement, tu devrais avoir 1280 (0x0005 est devenu 0x0500)
 
Ensuite tu pourras épater ton prof en lui disant que tout entier long ou court qui traverse un réseau doit d'abord être converti en "représentation réseau" via la fonction  

  • "htons()" => "host to net short" => converti un short du host vers le net
  • "htonl()" => "host to net long" => converti un long du host vers le net


Et tout nombre arrivant du réseau doit être reconverti en nombre compréhensible par la machine via la fonction:

  • "ntohs()" => "net to host short" => converti un short du net vers le host
  • "ntohl()" => "net to host long" => converti un long du net vers le host


Pour reprendre l'exemple, précédent, tu écris "short j=htons(i)", tu balances "j" sur le réseau que tu récupères de l'autre coté dans un "short x" et tu affiches "ntohs(x)". Tu devrais retrouver ton "5"


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

Marsh Posté le 25-03-2006 à 10:32:33    

Taz a écrit :

pourquoi tu veux faire ça en fait ?


 
je dois transferer ma structure via socket (sans mapping) entre une machine x86 et une SPARC et apparamment l'alignement par defaut des octets sur ces 2 machines n'est pas le meme, cela me créeait donc des decalages lorsque je voulais relire mes données coté SPARC (mon double etait decalé de 2 octets et donc le double que je lisais etait faux car ses 2 octets de poids fort correspondaient aux octets utilisés sur la x86 pour aligner et les 2 octets de poids faible correspondait aux octets de poids fort)
 

Sve@r a écrit :

Pas besoin d'une structure pour ça. Tu écris "short i=5", tu balances "i" sur ta socket et tu regardes ton nombre à l'arrivée. Normallement, tu devrais avoir 1280 (0x0005 est devenu 0x0500)
 
Ensuite tu pourras épater ton prof en lui disant que tout entier long ou court qui traverse un réseau doit d'abord être converti en "représentation réseau" via la fonction  

  • "htons()" => "host to net short" => converti un short du host vers le net
  • "htonl()" => "host to net long" => converti un long du host vers le net


Et tout nombre arrivant du réseau doit être reconverti en nombre compréhensible par la machine via la fonction:

  • "ntohs()" => "net to host short" => converti un short du net vers le host
  • "ntohl()" => "net to host long" => converti un long du net vers le host


Pour reprendre l'exemple, précédent, tu écris "short j=htons(i)", tu balances "j" sur le réseau que tu récupères de l'autre coté dans un "short x" et tu affiches "ntohs(x)". Tu devrais retrouver ton "5"


 
oui j'utilise ces 2 fonctions pour les int et les float, mias cela ne marche pas pour les doubles
 
et l'utilisation de structure m'est imposé

Message cité 1 fois
Message édité par ArthurDent le 25-03-2006 à 10:33:31
Reply

Marsh Posté le 25-03-2006 à 15:38:01    

Il y a la librairie ``xdr`` de Sun pour les échanges réseaux normalisés (RFC1014).

Reply

Marsh Posté le 25-03-2006 à 17:25:18    

nargy a écrit :

Il y a la librairie ``xdr`` de Sun pour les échanges réseaux normalisés (RFC1014).


 
oui mais là aussi le tp nous "interdit" de  l'utiliser

Reply

Marsh Posté le 25-03-2006 à 17:39:53    

:lol: ok il est pas sympa le prof :)

Reply

Marsh Posté le 25-03-2006 à 19:22:05    

ArthurDent a écrit :

oui j'utilise ces 2 fonctions pour les int et les float, mias cela ne marche pas pour les doubles


 
C'est fun d'utiliser "ntohl()" et "htonl()" avec des float... mais puisque le prof t'intedit d'utiliser XDR il te suffit d'utiliser intelligemment "ntohs()" et "htons()" pour créer des fonctions "ntohd()" et "htond()"
 

Code :
  1. /* Fonction de conversion de double "local" en double "réseau" */
  2. double htond(
  3. double hostdbl)      /* Nombre à convertir */
  4. {
  5. /* Déclaration des variables */
  6. ushort i;       /* Indice de boucle */
  7. ushort j;       /* Indice de boucle */
  8. ushort convert;      /* Zone de conversion */
  9. union {
  10.  double val;      /* Stockage du nombre */
  11.  unsigned char p[8];     /* Décomposition du nombre */
  12. }zone;        /* Zone de travail */
  13. /* Remplisssage nombre à convertir */
  14. zone.val=hostdbl;
  15. /* Travail sur chaque extrémités de la zone en revenant vers le centre */
  16. for (i=0, j=7; i < j; i++, j--)
  17. {
  18.  /* Copie des parties de la zone dans un entier court de conversion */
  19.  convert=(zone.p[i] << 8) + zone.p[j];
  20.  /* Conversion de l'entier court par la primitive normalisée "htons" */
  21.  convert=htons(convert);
  22.  /* Recopie des octets de l'entier court dans les parties de la zone */
  23.  zone.p[i]=convert >> 8;
  24.  zone.p[j]=convert & 0x00ff;
  25. }
  26. /* Renvoi nombre converti */
  27. return(zone.val);
  28. }
  29. /* Fonction de conversion de double "réseau" en double "local" */
  30. double ntohd(
  31. double netdbl)      /* Nombre à convertir */
  32. {
  33. /* Déclaration des variables */
  34. ushort i;       /* Indice de boucle */
  35. ushort j;       /* Indice de boucle */
  36. ushort convert;      /* Zone de conversion */
  37. union {
  38.  double val;      /* Stockage du nombre */
  39.  unsigned char p[8];     /* Décomposition du nombre */
  40. }zone;        /* Zone de travail */
  41. /* Remplisssage nombre à convertir */
  42. zone.val=netdbl;
  43. /* Travail sur chaque extrémités de la zone en revenant vers le centre */
  44. for (i=0, j=7; i < j; i++, j--)
  45. {
  46.  /* Copie des parties de la zone dans un entier court de conversion */
  47.  convert=(zone.p[i] << 8) + zone.p[j];
  48.  /* Conversion de l'entier court par la primitive normalisée "ntohs" */
  49.  convert=ntohs(convert);
  50.  /* Recopie des octets de l'entier court dans les parties de la zone */
  51.  zone.p[i]=convert >> 8;
  52.  zone.p[j]=convert & 0x00ff;
  53. }
  54. /* Renvoi nombre converti */
  55. return(zone.val);
  56. }

Message cité 1 fois
Message édité par Sve@r le 25-03-2006 à 19:24:21

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

Marsh Posté le 25-03-2006 à 19:53:40    

Sve@r a écrit :

C'est fun d'utiliser "ntohl()" et "htonl()" avec des float... mais puisque le prof t'intedit d'utiliser XDR il te suffit d'utiliser intelligemment "ntohs()" et "htons()" pour créer des fonctions "ntohd()" et "htond()"
 

Code :
  1. /* Fonction de conversion de double "local" en double "réseau" */
  2. double htond(
  3. double hostdbl)      /* Nombre à convertir */
  4. {
  5. /* Déclaration des variables */
  6. ushort i;       /* Indice de boucle */
  7. ushort j;       /* Indice de boucle */
  8. ushort convert;      /* Zone de conversion */
  9. union {
  10.  double val;      /* Stockage du nombre */
  11.  unsigned char p[8];     /* Décomposition du nombre */
  12. }zone;        /* Zone de travail */
  13. /* Remplisssage nombre à convertir */
  14. zone.val=hostdbl;
  15. /* Travail sur chaque extrémités de la zone en revenant vers le centre */
  16. for (i=0, j=7; i < j; i++, j--)
  17. {
  18.  /* Copie des parties de la zone dans un entier court de conversion */
  19.  convert=(zone.p[i] << 8) + zone.p[j];
  20.  /* Conversion de l'entier court par la primitive normalisée "htons" */
  21.  convert=htons(convert);
  22.  /* Recopie des octets de l'entier court dans les parties de la zone */
  23.  zone.p[i]=convert >> 8;
  24.  zone.p[j]=convert & 0x00ff;
  25. }
  26. /* Renvoi nombre converti */
  27. return(zone.val);
  28. }
  29. /* Fonction de conversion de double "réseau" en double "local" */
  30. double ntohd(
  31. double netdbl)      /* Nombre à convertir */
  32. {
  33. /* Déclaration des variables */
  34. ushort i;       /* Indice de boucle */
  35. ushort j;       /* Indice de boucle */
  36. ushort convert;      /* Zone de conversion */
  37. union {
  38.  double val;      /* Stockage du nombre */
  39.  unsigned char p[8];     /* Décomposition du nombre */
  40. }zone;        /* Zone de travail */
  41. /* Remplisssage nombre à convertir */
  42. zone.val=netdbl;
  43. /* Travail sur chaque extrémités de la zone en revenant vers le centre */
  44. for (i=0, j=7; i < j; i++, j--)
  45. {
  46.  /* Copie des parties de la zone dans un entier court de conversion */
  47.  convert=(zone.p[i] << 8) + zone.p[j];
  48.  /* Conversion de l'entier court par la primitive normalisée "ntohs" */
  49.  convert=ntohs(convert);
  50.  /* Recopie des octets de l'entier court dans les parties de la zone */
  51.  zone.p[i]=convert >> 8;
  52.  zone.p[j]=convert & 0x00ff;
  53. }
  54. /* Renvoi nombre converti */
  55. return(zone.val);
  56. }



 
oué nan, j'ai rien dit pour les floats.
 
la fonction de conversion je l'ai fait a coup de memcpy en passant la taille de la donnée en parametre afin de pouvoir le reutiliser avec autre chose que des doubles

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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