taille de structure == somme éléments?

taille de structure == somme éléments? - C - Programmation

Marsh Posté le 19-12-2007 à 15:41:52    

Bonjour,
Pourquoi est-ce que ce programme suivant:
 

Code :
  1. #include <stdio.h>
  2. typedef struct
  3. {
  4.     unsigned short a;
  5.     unsigned long b;
  6. }structure_ab;
  7. typedef struct
  8. {
  9.     unsigned short a;
  10. }structure_a;
  11. typedef struct
  12. {
  13.     unsigned long b;
  14. }structure_b;
  15. int main(void)
  16. {
  17.     printf("struture a :  %u\n",sizeof(structure_a));
  18.     printf("struture b :  %u\n",sizeof(structure_b));
  19.     printf("struture ab : %u\n",sizeof(structure_ab));
  20.     return 0;
  21. }


 
Donne:
 

Citation :

structure a : 2
structure b : 4
structure ab : 8


 
et pas:
 

Citation :

structure a : 2
structure b : 4
structure ab : 6


 
Je vois mal où est mon erreur.

Reply

Marsh Posté le 19-12-2007 à 15:41:52   

Reply

Marsh Posté le 19-12-2007 à 16:11:38    

il n'y pas d'erreur, il y a du bourrage ce qui est tout à fait normal quand ça n'est pas obligatoire.

Reply

Marsh Posté le 19-12-2007 à 16:16:59    

Taz veut dire que ton compilo a préféré aligner le membre 'b' de type 'unsigned long' sur un multiple de 4 octets... Il a donc ajouté deux octets inutilisés après 'a'...
C'est parfois moins pénalisant en temps d'accès... c'est même parfois obligatoire.
 
Edit: il y a parfois aussi "bourrage" en fin de structure pour les mêmes raisons car le compilo ne doit pas créer de problème d'alignement dans les tableaux...


Message édité par spotaszn le 19-12-2007 à 16:18:52
Reply

Marsh Posté le 19-12-2007 à 16:19:20    

Ah je connaissais pas le "bourrage". Et comment on fait si on veut lire un élément avec la fonction fread par exemple? On va lire 8 octets avec sizeof(structure_ab) en argument de fread. Alors qu'on veut en lire que 6.

Reply

Marsh Posté le 19-12-2007 à 16:28:59    

ngkreator a écrit :

Ah je connaissais pas le "bourrage". Et comment on fait si on veut lire un élément avec la fonction fread par exemple? On va lire 8 octets avec sizeof(structure_ab) en argument de fread. Alors qu'on veut en lire que 6.


Tu t'en occupes pas. Tu écris une struct et tu lis une struct. Tout le monde retrouve ses petits. C'est juste pas portable niveau format de fichier.

Reply

Marsh Posté le 19-12-2007 à 16:43:58    

Tu as une directive "#pragma pack", si tu veux modifier le comportement de l'alignement... mais faut pas faire n'importe quoi avec (les push/pop sont alors bien pratiques).

Reply

Marsh Posté le 19-12-2007 à 16:52:42    

spotaszn a écrit :

Tu as une directive "#pragma pack", si tu veux modifier le comportement de l'alignement... mais faut pas faire n'importe quoi avec (les push/pop sont alors bien pratiques).


je l'attendais celle là  :fou:  
 
Toujours les mêmes à conseiller des trucs que personne n'utilisent sauf pour coder un kernel.
(Le premier qui me dit "c'est pour coller à une représentation binaire" il a perdu)
 
Une petite astuce, si c'est possible, c'est d'ordonner tes membres dans ta struct par taille décroissante et les grouper par type.

Reply

Marsh Posté le 19-12-2007 à 16:57:22    

Merci à Taz pour cette mise en garde, on a vite fait de croire qu'on va coller à une représentation binaire mais on rencontre des problèmes d'endianess, donc de portabilité...
La question serait donc de savoir si le format de fichier est figé ou modifiable...

Reply

Marsh Posté le 19-12-2007 à 17:07:21    

Tu peux packer autant que tu veux sur sparc, ça ne donnera rien. Pour utiliser une représentation binaire portable, il faut la définir et l'implémenter en lisant octet par octet.
 
S'il s'agit d'un exercice, je pense que tout ça n'entre pas en compte. Il doit s'agir d'écrire un fichier et de le relire.

Reply

Marsh Posté le 19-12-2007 à 18:54:29    

Un exercice? Non je m'amuse à travailler les fichiers bmp.  Pour l'instant mon programme fonctionne en lisant octet par octet (fgetc) le fichier bmp pour les insérer dans un tableau. Maintenant je veux faire ça avec des structures à la place des tableaux. Et j'essaye de lire et écrire mes structures (fread) en respectant le format bmp. C'est beaucoup plus pratique ... à 1ère vue.
 
Le problème c'est que je récupère des images bmp et c'est pas moi qui choisit le format d'écriture. Donc si j'ai une structure de 16 octets (alors que la somme des variables fait 14) qui représente l'entête du bmp et que fread m'écrit 16 octets (au lieu des 14 octets requis par le bmp) ça va pas aller.


Message édité par ngkreator le 19-12-2007 à 18:59:45
Reply

Marsh Posté le 19-12-2007 à 18:54:29   

Reply

Marsh Posté le 19-12-2007 à 19:11:45    

lit octet par octet et remplis ta structure. Forcer une binary representation == pas bien

Reply

Marsh Posté le 19-12-2007 à 19:21:14    

Ok, dommage je trouvais fread pratique.

Reply

Marsh Posté le 19-12-2007 à 22:14:33    

il est préférable d'exporter et d'importer les champs de ta structure un par un en mettant au point un format d'enregistrement comme un simple tag/longueur/valeur.  
Tu pourra ainsi gérer par la même occasion des modifications de la structure comme l'ajout ou la suppresion d'un champs et les modification de types

Reply

Marsh Posté le 23-12-2007 à 00:29:26    

ngkreator a écrit :

Ok, dommage je trouvais fread pratique.


Tu peux utiliser fread, mais juste pas directement sur ta structure comme expliqué.

Reply

Marsh Posté le 23-12-2007 à 11:55:55    

Ok donc en fait j'ai fait des fonctions qui lisent une structure et la mettent dans un tableau, dans le bon ordre et la bonne taille. Après c'est vrai que j'y avait pas pensé, je peux écrire le tableau en un seul coup avec fread pour l'écrire dans le fichier.
 

Code :
  1. unsigned char * convertir_header_tab(const t_header * header,char endianess)
  2. {
  3.     unsigned char *tab = NULL;
  4.     size_t i;
  5.     tab = malloc(HEADER_SIZE);
  6.     if(tab != NULL)
  7.     {
  8.         for(i = 0; i < sizeof(header->format); i++)
  9.             tab[OFFSET_HEADER_FORMAT+i]
  10.             = octet(header->format,sizeof(header->format),i+1,endianess);
  11.         for(i = 0; i < sizeof(header->size); i++)
  12.             tab[OFFSET_HEADER_SIZE+i]
  13.             = octet(header->size,sizeof(header->size),i+1,endianess);
  14.         for(i = 0; i < sizeof(header->reserved1); i++)
  15.             tab[OFFSET_HEADER_RESERVED1+i]
  16.             = octet(header->reserved1,sizeof(header->reserved1),i+1,endianess);
  17.         for(i = 0; i < sizeof(header->reserved2); i++)
  18.             tab[OFFSET_HEADER_RESERVED2+i]
  19.             = octet(header->reserved2,sizeof(header->reserved2),i+1,endianess);
  20.         for(i = 0; i < sizeof(header->offsetBits); i++)
  21.             tab[OFFSET_HEADER_OFFSETBITS+i]
  22.             = octet(header->offsetBits,sizeof(header->offsetBits),i+1,
  23.                     endianess);
  24.     }
  25.     return tab;
  26. }


 
Pour l'endianess je devais plutôt utiliser une constante définie par une marco du style:
 
#ifdef WINDOWS ENDIANESS 'l'
#elif LINUX ...
 
C'est une bonne idée?

Reply

Marsh Posté le 23-12-2007 à 12:26:46    

deja l'endiannes ca depend pas de l'OS mais plutot de la famille du processeur :o
 
et non, c'est atroce. La bonne stratégie, à mon sens, est de sérialiser entiérement la SDD de manière endian-independant, et de reconstrurie les chsoes proprements à chaque fois.

Reply

Marsh Posté le 23-12-2007 à 12:59:58    

Sérialiser la SDD?  
Ah pour l'endianess je savais pas. La différence serait plutôt PC <-> Mac alors. Comment prendre en compte ça pour que ça soit portable?
 
Pour être plus clair voilà ma démarche:
 
- lecture du fichier bmp et enregistrement des valeurs en prennant en compte l'endianess
- insertion des valeurs dans une structure
- lecture des valeurs à partir de la structure
- enregistrement du fichier bmp (à partir des valeurs) en prennant en compte l'endianess
 
Donc je ne fais la conversion qu'a l'écriture et la lecture.

Message cité 1 fois
Message édité par ngkreator le 23-12-2007 à 13:02:39
Reply

Marsh Posté le 23-12-2007 à 21:45:41    

ngkreator a écrit :

Sérialiser la SDD?  
Ah pour l'endianess je savais pas. La différence serait plutôt PC <-> Mac alors.


avec les mac x86, non...

Citation :

Comment prendre en compte ça pour que ça soit portable?


On écrit du code portable. On définit un format de données indépendant de toute machine et on s'y tient. C'est pas plus compliqué que ça.
 
Ici, c'est le format BMP qui est la référence. Il faut faire ce qui est demandé, c'est tout. Si c'est bien fait (octet/octets, décalages...) c'est portable.
 


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

Sujets relatifs:

Leave a Replay

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