Probleme de taille sur une structure

Le
Clement
Bonjours


En fait je developpe un petit logiciel de steganographie qui cache un texte
dans une image BMP.

Precision:
Je code sur un PC x86 et en c standart.

Mon probleme c'est que apres avoir defini la structure de l'entete du
fichier BMP lors de la lecture avec un fread je me retrouve avec des
informations errone dans les champs sauf dans type qui contient bien MB
(little-endian).

Or je me suis rendu compte que lorsque je fait un sizeof(bmp_header) la
taille de cette structure fait 16 octets alors qu'elle derait en faire
14=2+4+2+2+4. Mes types font bien la bonne taille car j'ai verifie, comme
vous pouvez le voir ci-dessous.

typedef unsigned int Uint32;
typedef unsigned short Uint16;
typedef unsigned char Uint8;

typedef struct bmp_header{
Uint16 type; /* Magic identifier "BM" */
Uint32 size; /* taille du fichier en octets */
Uint16 reserved1; /* Reserve tjrs a 0 */
Uint16 reserved2; /* Reserve tjrs a 0 */
Uint32 offset; /* Offset to image data, bytes */
} bmp_header;


printf("Uint8 : %dUint16 : %dUint32 : %d", sizeof(Uint8),
sizeof(Uint16), sizeof(Uint32));

printf("bmp_header : %d", sizeof(bmp_header));

Ce qui affiche

Uint8 : 1
Uint16 : 2
Uint32 : 4
bmp_header : 16

Merci par avance de votre reponse.
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
AG
Le #601369
Clement wrote:

Mon probleme c'est que apres avoir defini la structure de l'entete du
fichier BMP lors de la lecture avec un fread je me retrouve avec des
informations errone dans les champs sauf dans type qui contient bien MB
(little-endian).
As tu affiché correctement le résultat de ton fread ? ça peut être la source de

tes erreurs. Comment transfers tu tes données du buffer de fread vers ta
structure ?


Or je me suis rendu compte que lorsque je fait un sizeof(bmp_header) la
taille de cette structure fait 16 octets alors qu'elle derait en faire
14=2+4+2+2+4. Mes types font bien la bonne taille car j'ai verifie, comme
vous pouvez le voir ci-dessous.
Il peut y avoir des bits de padding dans ta structure, qui font que la taille de

la structure est plus grande que la somme des tailles des types qui la compose.
C'est normal.

Thierry Boudet
Le #601162
On 2004-04-05, Clement

Precision:
Je code sur un PC x86 et en c standart.

A ce propos, existe-t-il une liste de tous les compilateurs C

existants ou ayant existés pour cette plate-forme ?
Question plus historique que technique, d'ailleurs...



--
http://tth.vaboofer.com/Cette/lycee_paul_valery.html

Yves ROMAN
Le #601161

Bonjours

En fait je developpe un petit logiciel de steganographie qui cache un texte
dans une image BMP.

Precision:
Je code sur un PC x86 et en c standart.

Mon probleme c'est que apres avoir defini la structure de l'entete du
fichier BMP lors de la lecture avec un fread je me retrouve avec des
informations errone dans les champs sauf dans type qui contient bien MB
(little-endian).

Or je me suis rendu compte que lorsque je fait un sizeof(bmp_header) la
taille de cette structure fait 16 octets alors qu'elle derait en faire
14=2+4+2+2+4. Mes types font bien la bonne taille car j'ai verifie, comme
vous pouvez le voir ci-dessous.

typedef unsigned int Uint32;
typedef unsigned short Uint16;
typedef unsigned char Uint8;

typedef struct bmp_header{
Uint16 type; /* Magic identifier "BM" */
Uint32 size; /* taille du fichier en octets */
Uint16 reserved1; /* Reserve tjrs a 0 */
Uint16 reserved2; /* Reserve tjrs a 0 */
Uint32 offset; /* Offset to image data, bytes */
} bmp_header;

printf("Uint8 : %dnUint16 : %dnUint32 : %dn", sizeof(Uint8),
sizeof(Uint16), sizeof(Uint32));

printf("bmp_header : %dn", sizeof(bmp_header));

Ce qui affiche

Uint8 : 1
Uint16 : 2
Uint32 : 4
bmp_header : 16



Il s'agit d'un problème de padding : la structure C contient 2 octets de padding
pour aligner les champs Uint32 sur une fontière de mot de 32bits (surement entre
type et size).

Pour résoudre ton problème, il existe 3 solutions :

- soit lire/écrire ta structure champ par champ :
fread(&header.type,sizeof(header.type),1,fic)
fread(&header.size,sizeof(header.size),1,fic)
fread(&header.reserved1,sizeof(header.reserved1),1,fic)
fread(&header.reserved2,sizeof(header.reserved2),1,fic)
fread(&header.offset,sizeof(header.offset),1,fic)

- soit utiliser des options de compilation pour empêcher le padding dans ta
structure : ça dépend du compilateur et c'est potentiellement dangereux et
risque de poser des problèmes d'alignement à l'exécution :
ex: #pragma pack(1) avant ta définition de structure et #pragma pack() après
avec VisualC++

- soit lire la taille voulue, et affecter champ par champ, mais je crains que ça
ne pose des problèmes d'alignement à l'exécution.
Uint16 tableau[7] ;
fread(tableau,14,1,fic)
header.type = tableau[0] ;
header.size = *((Uint32 *)(tableau+1)) ;
header.reserved1 = tableau[3] ;
header.reserved2 = tableau[4] ;
header.offset = *((Uint32 *)(tableau+5)) ;

Antoine Leca
Le #600944
En , Thierry Boudet va escriure:
On 2004-04-05, Clement

Je code sur un PC x86 et en c standart.

A ce propos, existe-t-il une liste de tous les compilateurs C

existants ou ayant existés pour cette plate-forme ?
Question plus historique que technique, d'ailleurs...


ÀMHA, c'est impossible à faire. C'est le genre de boulot où tu as à peine
émis une information qu'elle est déjà obsolète...

<URL:http://www.pestpatrol.com/Support/About/About_the_Pest_Analysis_System.
asp#compiler>
en liste 80 qu'ils sauraient repérer, pas tous pour le C, mais quand même,
l'enorme majorité...

Je me rappelle avoir vu quelque part une liste ds compilos "libres", il
devait y en avoir au moins 40.

Sans compter que l'on peut en rajouter à loisir. Par exemple, j'ai dans un
coin un projet de compilo C pour x86, utilisant la base lcc, mais avec comme
particularité que les char font 16 bits (utilisant la propriété que l'API NT
fonctionne avec des caractères de cette taille). Inutile de dire que c'est
bien sûr « du C standard » :-).


Antoine


Alexandre BACQUART
Le #605141
Yves ROMAN wrote:

Bonjours

En fait je developpe un petit logiciel de steganographie qui cache un texte
dans une image BMP.

Precision:
Je code sur un PC x86 et en c standart.

Mon probleme c'est que apres avoir defini la structure de l'entete du
fichier BMP lors de la lecture avec un fread je me retrouve avec des
informations errone dans les champs sauf dans type qui contient bien MB
(little-endian).

Or je me suis rendu compte que lorsque je fait un sizeof(bmp_header) la
taille de cette structure fait 16 octets alors qu'elle derait en faire
14=2+4+2+2+4. Mes types font bien la bonne taille car j'ai verifie, comme
vous pouvez le voir ci-dessous.

typedef unsigned int Uint32;
typedef unsigned short Uint16;
typedef unsigned char Uint8;

typedef struct bmp_header{
Uint16 type; /* Magic identifier "BM" */
Uint32 size; /* taille du fichier en octets */
Uint16 reserved1; /* Reserve tjrs a 0 */
Uint16 reserved2; /* Reserve tjrs a 0 */
Uint32 offset; /* Offset to image data, bytes */
} bmp_header;

printf("Uint8 : %dnUint16 : %dnUint32 : %dn", sizeof(Uint8),
sizeof(Uint16), sizeof(Uint32));

printf("bmp_header : %dn", sizeof(bmp_header));

Ce qui affiche

Uint8 : 1
Uint16 : 2
Uint32 : 4
bmp_header : 16




Il s'agit d'un problème de padding : la structure C contient 2 octets de padding
pour aligner les champs Uint32 sur une fontière de mot de 32bits (surement entre
type et size).

Pour résoudre ton problème, il existe 3 solutions :

- soit lire/écrire ta structure champ par champ :
fread(&header.type,sizeof(header.type),1,fic)
fread(&header.size,sizeof(header.size),1,fic)
fread(&header.reserved1,sizeof(header.reserved1),1,fic)
fread(&header.reserved2,sizeof(header.reserved2),1,fic)
fread(&header.offset,sizeof(header.offset),1,fic)


C'est la méthode la plus sure.

- soit utiliser des options de compilation pour empêcher le padding dans ta
structure : ça dépend du compilateur et c'est potentiellement dangereux et
risque de poser des problèmes d'alignement à l'exécution :
ex: #pragma pack(1) avant ta définition de structure et #pragma pack() après
avec VisualC++


Oui, dangereux car la norme ne garantit pas que les données seront
agençées comme elles sont déclarées. De plus, même si le plus souvent ça
marche, il faut souligner que forcer le compilateur à agencer le données
comme on veut engendre une perte en efficacité de traitement de la
structure sur tout le programme.

- soit lire la taille voulue, et affecter champ par champ, mais je crains que ça
ne pose des problèmes d'alignement à l'exécution.
Uint16 tableau[7] ;
fread(tableau,14,1,fic)
header.type = tableau[0] ;
header.size = *((Uint32 *)(tableau+1)) ;
header.reserved1 = tableau[3] ;
header.reserved2 = tableau[4] ;
header.offset = *((Uint32 *)(tableau+5)) ;


Pas portable, et encore plus dangereux car ça se compilera partout et
les bugs big-endian vs. little-endian, on a déjà donné :)

--
Tek
int main() {printf("Free The World !");} /* copyleft */


Publicité
Poster une réponse
Anonyme