sscanf et lecture de réel

sscanf et lecture de réel - C - Programmation

Marsh Posté le 28-07-2006 à 16:40:37    

Bonjour tous le monde !
 
Je rencontre un problème lorsque je cherche à lire des réels depuis un buffer : impossible de faire fonctionner le sscanf ... encore ...
Je lis en fait une ligne de 250 caractères dont les caractère 159 à 165 represente un litrage en mL, dans mon exemple : 1023800 (autre ex : 0048600)
Voila plusieurs bouts de code pour comprendre le problème :
 
s->data[i].volumeCarbu --> float
tmp --> int

---------------------
 

Code :
  1. for (k=158; k < 165; k++)
  2.                            buffer[k-158] = ligne[k];
  3.                        buffer[k-158] = '\0';
  4.                        if (1 != sscanf(buffer,"%f",&s->data[i].volumeCarbu))
  5.                           return 0;
  6.                        s->data[i].volumeCarbu /= 1000.0f;


Résultat :
Un nombre qui n'a rien a voir du type : 1218173.0
---------------------
 

Code :
  1. for (k=158; k < 165; k++)
  2.                            buffer[k-158] = ligne[k];
  3.                        buffer[k-158] = '\0';
  4.                        if (1 != sscanf(buffer,"%d",&tmp))
  5.                           return 0;
  6.                        s->data[i].volumeCarbu = tmp/1000.0f;


Résultat :
Le bon nombre mais sans les décimales (tronqué) : 1023.0
 
 
--> Impossible d'avoir le bon résultat : 1023.8
 
 
Est ce que quelqu'un aurait une solution ?
Merci d'avance ;) !

Message cité 1 fois
Message édité par ThibB le 28-07-2006 à 16:57:54

---------------
Visiter mon site
Reply

Marsh Posté le 28-07-2006 à 16:40:37   

Reply

Marsh Posté le 28-07-2006 à 16:47:58    

C'est bien un float ton nombre?

Reply

Marsh Posté le 28-07-2006 à 16:51:23    

pourquoi %d dans le second morceau de code ?


---------------
Töp of the plöp
Reply

Marsh Posté le 28-07-2006 à 16:53:57    

Oui autant pour moi j'ai pas mis les type de variable :

s->data[i].volumeCarbu --> float
tmp --> int

 
L'idée de tmp c'est de récupérer la valeur dans un entier (à la base c'est une valeur entière), mais une fois divisé par 1000 elle devient décimal, d'ou le float.


Message édité par ThibB le 28-07-2006 à 16:54:42

---------------
Visiter mon site
Reply

Marsh Posté le 28-07-2006 à 17:13:36    

Si c'est pour faire un sscanf(buffer,"%f",&s->data[i].volumeCarbu)), autant faire un strtod(buffer, NULL); ce sera plus sûr.  
(les Xscanf sont trèèèèèèès difficiles à utiliser).

Reply

Marsh Posté le 28-07-2006 à 17:19:11    

ou atof, mais c'est moins bien (juste pour rajouter une solution)


---------------
Töp of the plöp
Reply

Marsh Posté le 28-07-2006 à 17:21:09    

Je n'avais pas pensé à utliser cette fonction mais malheureusement ca ne passe pas :(
 
J'ai mis :

Code :
  1. s->data[i].volumeCarbu = (float)strtod(buffer, NULL);


Et j'obtien :
-2147483648,c


---------------
Visiter mon site
Reply

Marsh Posté le 28-07-2006 à 17:22:46    

Même résultat avec atof :(


---------------
Visiter mon site
Reply

Marsh Posté le 28-07-2006 à 17:35:15    

Mets errno à 0, avant le strtod(), et regarde sa valeur après.

Reply

Marsh Posté le 28-07-2006 à 17:38:27    

Et avec un "long double"?

Code :
  1. long double f=0;
  2. char s[100]="123456789.123";
  3. sscanf(s,"%Lf",&f);
  4. fprintf(stdout,"%Lf\n",f);

Reply

Marsh Posté le 28-07-2006 à 17:38:27   

Reply

Marsh Posté le 28-07-2006 à 18:07:02    

Pour errno elle vaut toujours 0 après le strtod() :s
Et le long double ne résoud pas le problème non plus ...
 
En tout cas merci de me donner vos idées ;)


---------------
Visiter mon site
Reply

Marsh Posté le 28-07-2006 à 18:14:52    

Est que quelqu'un aurait une idée de la cause du problème dans le second bout de code ?
J'ai utilisé le debugger pour voir ce qu'il se passait dans ce cas la : tmp prend bien la bonne valeur (qui est donc un entier), mais c'est l'opération suivante (s->data[i].volumeCarbu = tmp/1000.0f;) qui donne un résultat entier ...


---------------
Visiter mon site
Reply

Marsh Posté le 28-07-2006 à 20:22:14    

eh bien essaye s->data[i].volumeCarbu = ((float)tmp)/1000.0f
ce serait d'ailleur, sans doute meilleur avec double.
Pour information, les fonctions atoX ne sont plus utilisables depuis 1989 cf http://www.developpez.net/forums/s [...] stcount=19

Reply

Marsh Posté le 28-07-2006 à 20:30:34    

ThibB a écrit :

Bonjour tous le monde !
 
Je rencontre un problème lorsque je cherche à lire des réels depuis un buffer : impossible de faire fonctionner le sscanf ... encore ...
Je lis en fait une ligne de 250 caractères dont les caractère 159 à 165 represente un litrage en mL, dans mon exemple : 1023800 (autre ex :  
<...>
Est ce que quelqu'un aurait une solution ?


 
A l'avenir, poste du code compilabel (j'ai passé 20 minutes à réinventer ce qui manquait...)
 
Ceci a l'air de fonctionner. Mais je recommande double au lieu de float. Meilleure précision, meilleures performances (pas de conversions).

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. /* 0 | 1 */
  4. #define DOUBLE 0
  5. struct data
  6. {
  7. #if DOUBLE
  8.    double volumeCarbu;
  9. #else
  10.    float volumeCarbu;
  11. #endif
  12. };
  13. struct x
  14. {
  15.    struct data data[1];
  16. };
  17. static int f (struct x *s, char const *ligne, int i)
  18. {
  19.    char buffer[20];
  20.    {
  21.       size_t k;
  22.       for (k = 158; k < 165; k++)
  23.       {
  24.          buffer[k - 158] = ligne[k];
  25.       }
  26.       buffer[k - 158] = '\0';
  27.    }
  28. #if DOUBLE
  29.    if (1 != sscanf (buffer, "%lf", &s->data[i].volumeCarbu))
  30. #else
  31.    if (1 != sscanf (buffer, "%f", &s->data[i].volumeCarbu))
  32. #endif
  33.    {
  34.       return 1;
  35.    }
  36.    s->data[i].volumeCarbu /= 1000;
  37.    return 0;
  38. }
  39. int main ()
  40. {
  41.    struct x x =
  42.    {
  43.       0
  44.    };
  45.    char ligne[200] = "";
  46.    /* 1023800 ml */
  47.    ligne[158] = '0';
  48.    ligne[159] = '1';
  49.    ligne[160] = '0';
  50.    ligne[161] = '2';
  51.    ligne[162] = '3';
  52.    ligne[163] = '8';
  53.    ligne[164] = '0';
  54.    ligne[165] = '0';
  55.    int ret = f (&x, ligne, 0);
  56.    printf ("%f ret=%d\n", x.data[0].volumeCarbu, ret);
  57.    return 0;
  58. }



102.379997 ret=0
 
Press ENTER to continue.


avec double :  


102.380000 ret=0
 
Press ENTER to continue.


Message édité par Emmanuel Delahaye le 28-07-2006 à 20:33:33

---------------
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 30-07-2006 à 18:31:58    

OK merci, je test ca et je vous tiens au courant :)  
Je ferais gaffe la prochaine fois de donner les structures, les type de variables, etc ...


Message édité par ThibB le 30-07-2006 à 18:40:44

---------------
Visiter mon site
Reply

Sujets relatifs:

Leave a Replay

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