[C] Sprintf et transformation en octet

Fermé
boelraty Messages postés 2 Date d'inscription mercredi 30 juillet 2008 Statut Membre Dernière intervention 30 juillet 2008 - 30 juil. 2008 à 07:11
Mahmah Messages postés 496 Date d'inscription lundi 17 septembre 2007 Statut Membre Dernière intervention 22 juin 2010 - 30 juil. 2008 à 15:33
Bonjour,

Je suis actuellement en train de travailler sur un programme qui a besoin de créer des fichiers BMP. Pour cela la première chose à faire est de créer le header du fichier.

Pour le moment, je fais des fwrite(&data,2,f) : f étant mon fichier, 2 la longueur en octet et data la donnée par exemple BM pour le type de fichier. Au lieu de faire un fwrite pour chaque élément du header, j'aimerais sauver toute l'entête du fichier dans une variable genre char.

J'ai donc pensé utiliser la fonction sprintf. Le problême c'est que je n'arrive pas à convertir en octet mes variables.
J'ai cela :

sprintf(head, "424D%08X%08X%08X%08X%08X%08X%04X%04X%08X%08X%08X%08X%08X%08X", BMPHeaderLenght, ReservedBit, DataOffset, DataHeaderLenght, width, height, Planes, BPP, Compression, ImageSize, ResX, Resy, ColorUsed, ColorImportant);

Chaque variable est de type int. Les 08 ou 04 correspondent à la taille en octet que je veux pour la variable (4 ou 2). Le problème c'est que je n'obtiens pas le bon résultat. Par ex pour une variable avec la valeur 40, j'ai 00000028 avec le sprintf et dans le fichier j'ai 28000000, c'est pas dans le bon sens.

A part lire la chaîne à l'envers et écrire les valeurs dans l'ordre inverse que puis-je faire ???? Je ne sais pas si les %08X sont adaptés à ce que je veux faire. Et encore c'est pas tellement lire à l'envers, c'est lire à l'envers octet par octet : par ex 0001E036 doit donner 36E00100

Merci pour vos réponses.

4 réponses

Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
30 juil. 2008 à 09:24
Je ne comprends pas bien ton histoire.
En fait, le fait que ça soit à l'envers m'étonne déjà.
pour moi, le sprintf permet d'écrire du texte dans une variable et fwrite écris en binaire. MAIS une sortie en hexadécimal (donnée par %X) écrit du texte, par exemple si ton entier vaut dix, tu écrira "0A" dans ton texte, ce qui correspond aux entier 55 et 70 (par exemple, je n'ai pas vérifié) ce qui une fois écri en binaire te donnera tout à fait autre chose.
en C, normalement (à vérifier avec sizeof), char vaut 1 octet, int 4, short 2.
Donc, défini un pointeur d'octet : char* head; (Il faut faire attention, char est souvent vu comme un caractère, mais c'est aussi un entier, ce qui m'intéresse ici)
alloue lui la bonne taille, puis rempli le :
*(head + decalage_en_octet)=(short)/* ou int */ variable_a_stoker
0
Mahmah Messages postés 496 Date d'inscription lundi 17 septembre 2007 Statut Membre Dernière intervention 22 juin 2010 125
30 juil. 2008 à 11:27
Bonjour,

Un header de fichier respecte des spécifications qui en pratique permettent bien souvent de faire des structures. Ces structures pourront être écrites facilement dans un fichier avec un fwrite.
EDIT. : exemple FIN EDIT.

L'inversion est normale. C'est la simple différence entre les machines Big Endian et Little Endian. Quand un PC écrira 1 soit 0x00000001 pour un humain en 32 bits, il l'écrira en inversant les octets, soit 01 00 00 00. Un Mac PowerPC écrira 00 00 00 01. C'est comme ça. (voir Endianess sur wikipédia Ainsi, en regardant ton fichier ou tes données avec un éditeur héxa ou la mémoire avec un debuggueur, c'est inversé. Ce n'est pas un bug. ;-) Même un simple int i = 22; est physiquement écrit 16 00 00 00 en mémoire.

M.
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
30 juil. 2008 à 13:21
exact, une structure est l'idéal. J'avais pensé au bigEndian, mais dans mon souvenir ça changeais AB en BA... (je copierai 100 fois comment fait le big endian en vrai)

Pour en revenir aux structure :
struct A{
int BMPHeaderLenght;short ReservedBit;int DataOffset;...etc
}
et ensuite, pour écrire :
write(&A,sizeof(A),f);
Le souci, c'est qu'en utilisant des structures avec des données alterné comme ça, tu peux avoir des alignements et donc des problèmes d'écriture.
0
Mahmah Messages postés 496 Date d'inscription lundi 17 septembre 2007 Statut Membre Dernière intervention 22 juin 2010 125
30 juil. 2008 à 15:33
Ah oui, en effet, il faut surveiller les alignements pour les membres la structure. Il n'y a pas de convention pour le faire mais bon nombre de compilateurs reconnaissent le :
#pragma pack( push, 1 )	//	alignement forcé de 1 octet

// Déclaration de la variable du type de la structure
...
// Ecriture/Lecture
...

#pragma pack( pop )



Sinon on doit pouvoir dire à n'importe quel compilateur quel alignement utiliser, mais c'est mieux de le faire localement dans le code quand c'est possible pour éviter de pénaliser toutes les structures/classes du programme.

Merci,
M.
0