fread

fread - C - Programmation

Marsh Posté le 28-04-2011 à 16:11:32    

Bonjour !
 
j'ai un soucis avec la fonction fread, lorsque je lui demande de lire 2octets elle ne m'en lit qu'un seul.
Je lis un fichier binaire.
 
voici mon code :
 

Code :
  1. int test(char *fichier_bin){
  2.           FILE * f = NULL;
  3.           char c;
  4.           short int i;
  5.  
  6.           f = fopen(fichier_bin,"rb" );
  7.           printf("taille d'un char  : %d \n",sizeof(char)); // 1octet  
  8.           printf("taille d'un short int : %d \n",sizeof(short int)); // 2octets
  9.           fread(&c,sizeof(c),1,f);
  10.           printf("%d\n",c); //  affiche la valeur decimale de l'octet
  11.           fread(&i,sizeof(i),2,f); // doit normalement lire 2octets
  12.           printf("%d\n",i); // affiche la valeur decimale des deux octets
  13.           fclose(f);
  14.           return 1;
  15. }


 
 
mon fichier binaire contient les bits suivants : 0000 1000 0010 0000 0000 0000   (je les espace exprès ici pour mieux voir , dans le fichier ils sont à la suite).
 
lorsque j'exécute mon programme, j'ai la sortie suivante :
 

Code :
  1. taille d'un char  : 1
  2. taille d'un short int : 2
  3. 8
  4. 32


 
8 est bien la valeur décimale de 0000 1000
mais 32 est la valeur décimale de 0010 0000, donc la fonction n'a lu qu'un octet alors que j'aurai voulu qu'elle me lise 0010 0000 0000 0000 et qu'elle affiche la valeur 8192
 
Voilà , je m'aide de cette page http://www.aly-abbara.com/utilitai [...] ffres.html pour faire mes conversions car je ne crois pas qu'il existe un symbole pour afficher les nombres binaires.
 
Voilà, j'espère avoir été assez claire,
 
je vous remercie d'avance
 
 
 
 

Reply

Marsh Posté le 28-04-2011 à 16:11:32   

Reply

Marsh Posté le 28-04-2011 à 16:15:32    

Version courte: ton problème se résume à: http://fr.wikipedia.org/wiki/Endianness
 
Pour savoir si tu as lu 2 octets, regarde le code de retour de fread.

Reply

Marsh Posté le 28-04-2011 à 16:22:28    

Citation :

         printf("%d\n",c); //  affiche la valeur decimale de l'octet


Avec printf(), il est recommandé de caster les paramètres (surtout si on utilise %d pour autre chose qu'un int), par exemple :

         printf("%d\n", (int)(c)); //  affiche la valeur decimale de l'octet


Message édité par olivthill le 28-04-2011 à 16:22:39
Reply

Marsh Posté le 28-04-2011 à 16:34:14    

fread me retourne effectivement 2. Donc a lu deux octets.
 
Mais pourquoi il m'affiche 32 alors ? comme s'il n'avait lu qu'un seul octet.
J'ai lu la page wikipédia, comment savoir comment mon ordinateur manipule les octets, si c'est en big-endian ou little-endian, pouvez vous m'éclaircir à ce sujet?
 
J'aimerais vraiment extraire les deux derniers octets de mon fichier, et je ne vois coment pour l'instant
 

Reply

Marsh Posté le 28-04-2011 à 16:35:25    

Merci olivthill, j'ai rectifié, mais les affichage c'était seulement pour vérifier les données extraites

Reply

Marsh Posté le 28-04-2011 à 16:40:42    


Code :
  1. fread(&i,sizeof(i),2,f); // doit normalement lire 2octets


 
Cet appel lit en réalité 2 fois 2 octets. Tu devrais mettre 1 en troisième paramètre.

Reply

Marsh Posté le 28-04-2011 à 16:41:49    

D'après ce que tu affiches, ton ordinateur est en little endian (tu dois probablement être sous Windows...).
 
Si tu veux afficher les deux octets, affiche ton contenu octet par octet alors :
 

Code :
  1. unsigned char buffer[2];
  2. fread(buffer, sizeof buffer, 1, f);
  3. printf("lu = %02x%02x\n", buffer[0], buffer[1]);


 
Arf, j'ai vu en plus que tu risque d'avoir un stack overflow dans ton programme :

Code :
  1. fread(&i,sizeof(i),2,f);


Tu lis 2 entiers de la taille de ta variable i. Or i ne peux contenir qu'un seul entier => stack overflow si tu n'est pas à la fin du fichier.
 

Citation :

Avec printf(), il est recommandé de caster les paramètres (surtout si on utilise %d pour autre chose qu'un int), par exemple :


Ce n'est pas nécessaire pour les types dont la taille est inférieure ou égale à celle d'un int à cause de la promotion implicite en int dans la partie vararg.

Message cité 1 fois
Message édité par tpierron le 28-04-2011 à 16:42:47
Reply

Marsh Posté le 28-04-2011 à 16:51:28    

tpierron a écrit :


D'après ce que tu affiches, ton ordinateur est en little endian (tu dois probablement être sous Windows...).


 
[Mode hors sujet on]
 
Je ne suis pas expert, mais il me semble que l'endianness dépend de l'architecture matérielle et non pas du système d'exploitation. Donc il pourrait aussi bien être sous Linux ! (Non, non, je ne lance pas de troll...)
 
[Mode hors sujet off]
 

Reply

Marsh Posté le 28-04-2011 à 17:00:08    

  1.Je remets mon code réctifié, effectivement j'ai fait des fautes de frappe dans le recopiage

Code :
  1. int test(char *fichier_bin){
  2.    2.
  3.    3.           FILE * f = NULL;
  4.    4.
  5.    5.           char c;
  6.    6.           short int i;
  7.    7. 
  8.    8.           f = fopen(fichier_bin,"rb" );
  9.    9.
  10.   10.           printf("taille d'un char  : %d \n",sizeof(char)); // 1octet   
  11.   11.           printf("taille d'un short int : %d \n",sizeof(short int)); // 2octets
  12.   12.
  13.   13.           lus = fread(&c,sizeof(char),1,f);
  14.   14.           printf("lus :%d , %d\n",lus,c); //  affiche la valeur decimale de l'octet
  15.   15.
  16.   16.           lus = fread(&i,sizeof(short int),1,f); // doit normalement lire 2octets
  17.   17.           printf("lus :%d, %d\n",lus,i); // affiche la valeur decimale des deux octets
  18.   18.
  19.   19.
  20.   20.           fclose(f);
  21.   21.
  22.   22.           return 1;
  23.   23.
  24.   24. }


 
 
et m'affiche  
 

Code :
  1. taille d'un char :1
  2. taille d'un short int :2
  3. lus :1, 8
  4. lus :1, 24608

Reply

Marsh Posté le 28-04-2011 à 17:00:32    

shaoyin a écrit :


Je ne suis pas expert, mais il me semble que l'endianness dépend de l'architecture matérielle et non pas du système d'exploitation. Donc il pourrait aussi bien être sous Linux ! (Non, non, je ne lance pas de troll...)


 [:talen] Arf, ce que je voulais surtout dire en fait, c'est que si tu es sous Windows, tu auras une archi little endian derrière.

Reply

Marsh Posté le 28-04-2011 à 17:00:32   

Reply

Marsh Posté le 28-04-2011 à 17:01:11    

j'utilise VMWARE, et je travaille avec Ubuntu.
Mais il est lancé à partir de Windows, je ne pense que cela soit considéré comme si je travaillais sous windows?


Message édité par rahela le 28-04-2011 à 17:02:10
Reply

Marsh Posté le 28-04-2011 à 17:08:26    

Mais le probleme, c'est que mon programme je vais l'envoyer à mes profs.
S'ils n'ont pas la même architecture que moi, cela risque de poser probleme dans la lecture de fichier, non ?

Reply

Marsh Posté le 28-04-2011 à 18:10:07    

rahela a écrit :

Mais le probleme, c'est que mon programme je vais l'envoyer à mes profs.
S'ils n'ont pas la même architecture que moi, cela risque de poser probleme dans la lecture de fichier, non ?

 

T'occupe pas de ça pour l'instant. Question bête mais quand même: ton fichier fait bien plus de 2 octets?

 

Sinon j'ai  trouvé ça:

 

Return Value
The total number of elements successfully read is returned as a size_t object, which is an integral data type.
If this number differs from the count parameter, either an error occured or the End Of File was reached.
You can use either ferror or feof to check whether an error happened or the End-of-File was reached.

 

-mettre la valeur de retour dans un size_t
-utiliser ferror et feof pour vérifier qu'un erreur est survenu ou qu'on est arrivé à la fin du fichier.


Message édité par gelatine_velue le 28-04-2011 à 18:12:13
Reply

Marsh Posté le 28-04-2011 à 19:15:16    

ouioui normalement il y a 5 octets a lire, j'ai reussi à parcourir le fichier octet par octet en appelant 5fois fread(&c,1,1,f); ca ne ma pas posé de probleme...

Reply

Marsh Posté le 28-04-2011 à 20:51:42    

J'ai compris !!!! il recupere bien deux octets, il recupere 0010 0000 et 0000 0000 , mais comme mon ordi est en little- endian il inverse les deux octets, ce qui donne  
0000 0000 0010 0000 et donc c'est pour cela qu'il m'affiche 32 ! tous les 0 avant deviennent insignifiants

Reply

Marsh Posté le 28-04-2011 à 20:52:04    

donc je dois effectuer une inversions?

Reply

Marsh Posté le 28-04-2011 à 21:43:40    

rahela a écrit :

donc je dois effectuer une inversions?


Non, lis ton fichier comme une suite d'octet. De cette manière :
 

Code :
  1. unsigned char buffer[2];
  2. fread(buffer, sizeof buffer, 1, f);
  3. printf("lu = %02x%02x\n", buffer[0], buffer[1]);


 
Maintenant si tu veux manipuler (de manière portable) tes deux octets comme un nombre, tu peux écrire :

Code :
  1. i = (buffer[0]<<8) | buffer[1];


 
Cela suppose donc que ton fichier stocke les entiers de plus d'un octet en big endian.
 
C'est chiant, mais c'est le prix à payer quand on manipule des données binaires.
 
Edit: le "unsigned" est important dans ce cas, car sinon tu auras une extension du signe pour les valeurs > 127, avec des valeurs complètement fausses si tu essayes de le reconvertir en entier avec des décalages binaires.


Message édité par tpierron le 28-04-2011 à 21:46:04
Reply

Marsh Posté le 28-04-2011 à 23:24:11    

Merci, ca marche impec !
 
une autre question, l'operation pourquoi ( ( (buffer[0]<<8) | buffer[1] ) & 0x1FFF ) ne marche pas ?
 
si je teste 0x2002 & 0x1FFF, ca marche correctement...


Message édité par rahela le 28-04-2011 à 23:41:03
Reply

Sujets relatifs:

Leave a Replay

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