IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

[ GCC -nostdinc , sans std* ]Convertir quelques types en une chaîne de caractères


Sujet :

C

  1. #1
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut [ GCC -nostdinc , sans std* ]Convertir quelques types en une chaîne de caractères
    Bonjour ,

    Je voudrais convertir un float en une chaîne de caractères sachant que je suis en train de faire un petit OS ( kernel 32 bits déjà fait, compilé avec gcc -nostdinc , donc la solution NE DOIT PAS FAIRE PARTIE DE std*.h ! ), et que je dois réécrire quelques fonctions C pour me lancer dans un compilateur C ( et un assembleur ) pour commencer à faire des petits logiciels pour mon OS .

    Une des fonctions C que je dois réécrire est printf .

    Jusqu'ici, ma fonction printf fonctionne avec %c, %s, %d, %%, et me manque encore le support de %f, %o, %p, %e, %x .

    Je dois donc savoir comment convertir un float en une chaîne de caractères, afficher un int en notation héxadécimal, scientifique, et octal non signé .

    Je voudrais, si possible, avoir une solution qui ne fait pas appel à des fonctions comme malloc ou strcmp ( je rechercherai encore plus sur leur code source dans le noyau linux 0.0.1 mais bon ce serait mieux sans ces fonctions ) .

    Merci beaucoup ,
    @+ .

  2. #2
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    J'ai oublié de préciser que j'utilise un i586-elf cross gcc sur cygwin si ça peut aider .

    Merci .

  3. #3
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 578
    Points
    41 578
    Par défaut
    Plutôt que "afficher un int en hexa", réfléchis sur une façon d'afficher un int dans n'importe quelle base. Bref, réimplémente la fonction non-standard itoa().

    Par contre, pour les floats, je ne sais pas trop. Moi, je l'afficherais plus ou moins comme deux int séparés par un point...

  4. #4
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    J'ai écris une petite fonction en C pour afficher un float à l'écran ( sachant que itoa, putchar et print marchent parfaitement et sont toutes réécrites ) après avoir vérifié l'execution du code ( en pensant comme un PC :p ) sur papier , mais il ne marche pas et se met dans une boucle infinie

    Voilà le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    void print_float(float val)
    {
    	float tmp=0;
    	float i=0;
    	float num=0;
    	int n=0;
    	num=val;
    	print(itoa((int)num,0));
    	putchar('.');
    	tmp=num-(int)num;
    	i=(int)num;
    	do {
    		tmp*=10;
    		print(itoa((int)tmp,0));
    		n++;
    		i+=(int)tmp / pow(10,n);
    		tmp=tmp-(int)tmp;
    	} while(num > i);
    }
    Est-ce peut-être dû au fait que j'accède à un pointeur ? sachant qu'un nombre étrange ( surement l'adresse dans laquelle pointe soit tmp , soit num ) est affiché au lieu de, par exemple, 8.469 .

    Si vous avez besoin d'une capture d'écran, faites-le moi savoir !

    Merci .

    PS : enlevé le break

  5. #5
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    - Les appels à itoa ne sont pas corrects en nombre de paramètres
    - Pourquoi ce break dans la boucle ?
    - La condition de sortie du while n'est jamais être remplie : i est une approximation par défaut de num
    - L'appel à pow est couteux en temps et inutile.

    Le code suivant donnera une idée de fonctionnement mais il reste beaucoup à travailler dessus pour le rendre opérationnel.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    void print_float(float val)
    {
       char tab[20];      // 20 au hasard. Choisir une valeur pertinente liée au 
                          //  nombre maximum de caractères de la partie entière
       print(itoa((int)val,tab,10));
       putchar('.');
       val=val-(int)val;
       do
       {
           val*=10;
           print(itoa((int)val,tab,10));
           val=val-(int)val;
       } while(val !=0);  // Plutôt d'ailleurs limiter le nombre de décimales (et faire
                          // un arrondi) que ce test grossier qui va nous donner un 
                         // paquet de décimales non significatives
    }

  6. #6
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    J'ai allumé le PC pour 2 secondes donc je n'ai pas le temps de dire plus, le break est là juste pour un débug , donc à ignorer svp .

    Et merci pour ta réponse, je lirai encore plus ce soir ^^

  7. #7
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    La fonction itoa fonctionne bien malgré les étranges paramètres que je lui donne ( biensûr , ce n'est pas une itoa comme celle qu'on trouve dans la libc mais le sera après lui avoir consacré un peu de temps ) donc le problème ne vient pas d'elle .

    Par exemple pour afficher 7.01 à l'écran, elle marchera ainsi ( ce qui est entre [ et ] constitue le contenu de la mémoire vidéo ) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    print(itoa((int)7.01,0));    |   [7******]
    putchar('.');                   |   [7.***** ]
    tmp=7.01-(int)7.01          |  =0.01
    i=(int)7.01;                    |  =7
    **Boucle**
    tmp*=10;                      |  =0.1
    putchar(itoa((int)tmp,0)); | [7.0****]
    n++;                             | =1
    i+=(int)tmp/pow(10,n);    | =7.0
    (num > i ) ?
    OUI :
    tmp*=10;                      |  =1
    putchar(itoa((int)tmp,0)); | [7.01***]
    n++;                             | =2
    i+=(int)tmp/pow(10,n);    | =7.01
    (num > i ) ? NON : STOP
    Et voilà ça semble marcher, bien sûr c'est peut-être est-ce dû à une petite bêtise dans le code .

  8. #8
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    J'ai réécri ma fonction itoa de façon à ce qu'elle prend en compte les arguments suivants : base, suffix ( pour préciser si on doit ajouter un 'h' à la fin si base=16 ), prefix ( pour préciser si on doit ajouter un '0x' au début si base=16 ) , ces deux derniers arguments verront leurs valeurs attribuées via des #define .

    Donc j'ai terminé la partie qui doit afficher/convertir un nombre en une chaine avec notation héxadécimal à l'écran ( je posterai le code après l'avoir retouché un peu pour l'optimiser et après l'avoir commenté bien sûr ) .

  9. #9
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par diogene Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    void print_float(float val)
    {
       char tab[20];      // 20 au hasard. Choisir une valeur pertinente liée au 
                          //  nombre maximum de caractères de la partie entière
       print(itoa((int)val,tab,10));
       putchar('.');
       val=val-(int)val;
       do
       {
           val*=10;
           print(itoa((int)val,tab,10));
           val=val-(int)val;
       } while(val !=0);  // Plutôt d'ailleurs limiter le nombre de décimales (et faire
                          // un arrondi) que ce test grossier qui va nous donner un 
                         // paquet de décimales non significatives
    }
    Toujours le même résultat :s

    Voilà une capture d'écran qui explique plus sur le problème ( déjà on sait que le problème ne vient que des floats puisque c'est la FPU ) :

    Images attachées Images attachées  

  10. #10
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    Je viens d'ajouter l'instruction assembleur FINIT dans mon secteur de boot pour initialiser les registres de la FPU, et apparemment Bochs n'affiche plus de message d'erreur concernant cette dernière .

    J'ai aussi crée une routine en assembleur ( fasm ) pour convertir un float en un int, en voici le code pour les interessés :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    format ms coff
    public ftol
     
    ftol:
    finit
    fld dword [esp+4]
    fistp dword [esp+4]
    mov eax,[esp+4]
    ret 4
    Donc maintenant quand je démarre mon noyau avec Bochs, il ne redémarre plus mais il affiche par exemple 28.130 avec votre code, et 28.000000000000000000quelquechose00000000000000000000 avec le mien au lieu de 28.07103 .

    Peut quelqu'un m'aider ?

    Merci .

  11. #11
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    En utilisant le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void print_float(float val)
    {
       char tab[20];      // 20 au hasard. Choisir une valeur pertinente liée au
                          //  nombre maximum de caractères de la partie entière
       printf("%s",itoa((int)val,tab,10));
       putchar('.');
       val=val-(int)val;
       do
       {
           val*=10;
           printf("%s",itoa((int)val,tab,10));
           val=val-(int)val;
       } while(val !=0);  // Plutôt d'ailleurs limiter le nombre de décimales (et faire
                          // un arrondi) que ce test grossier qui va nous donner un
                         // paquet de décimales non significatives
    }
    int main(void)
    {
       print_float( 28.0703);
        return EXIT_SUCCESS;
    }
    il m'affiche 28.07029914855....

  12. #12
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    C'est peut-être un pointeur qui est converti en int qui est affiché à l'écran ? ou du contenu de la mémoire après que le pointeur a dépassé la limite d'une variable , non ? Si les valeurs changent , ça doit être ça ( pas les mêmes OS aussi ) .

    Je vais essayer de me faire une version en assembleur pour voir exactement d'où vient le problème, je vous tiendrais au courant ^^

  13. #13
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    C'est peut-être un pointeur qui est converti en int qui est affiché à l'écran ? ou du contenu de la mémoire après que le pointeur a dépassé la limite d'une variable , non ? Si les valeurs changent , ça doit être ça ( pas les mêmes OS aussi )
    J'ai rien compris de ce que tu dis !

  14. #14
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    Je m'explique, par exemple pour 29.07 - 29 en C , gcc fait ceci en assembleur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    push 29.07
    finit
    fld dword [esp]
    push 29
    fsub dword [esp]
    fst dword [esp]
    mov eax,dword [esp] ; eax contiendra la valeur 0.07
    Le code fait donc appel aux instructions FPU, et dans la majorité des cas, elles renvoient des offsets ( pointeur donc ) au lieu d'un nombre de type long lorsqu'on fait une mauvaise manipulation .

    Pour la version en assembleur, j'ai déjà quelques problèmes pour appeller des fonctions C depuis un programme en assembleur compilé avec FASM au format MS COFF, je cherche un peu d'info sur les C-Call Convetions...

  15. #15
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 165
    Points : 62
    Points
    62
    Par défaut
    perso quand j'ai besoin d'afficher un float en chaine de caractere, je recupere la partie entiere et travailles en recursif sur chaque char et les affiches.
    Ensuite je recupere la partie apres la virgule et multiplie par la puissance de 10 que je veux (selon la precision souhaitee). Ainsi j'ai a nouveau un int et rebellote ...

  16. #16
    Membre régulier
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Points : 113
    Points
    113
    Par défaut
    Bonjour, il m'est impossible de désigner la puissance de 10 pour récupérer la partie décimale sachant que le nombre de chiffres de cette dernière n'est pas stable donc voilà .

    Puis le problème n'est pas là je pense, c'est juste une mauvaise manipulation de floats je pense ... et je précise que j'ignore toute autre solution avant d'avoir trouvé la source de mon problème ^_^

Discussions similaires

  1. Réponses: 1
    Dernier message: 31/12/2007, 08h12
  2. Réponses: 4
    Dernier message: 22/12/2006, 15h10
  3. Convertir une chaîne de caractères
    Par PedroBD dans le forum Langage
    Réponses: 3
    Dernier message: 13/11/2006, 17h25
  4. Réponses: 4
    Dernier message: 04/11/2006, 20h36
  5. Réponses: 2
    Dernier message: 22/04/2006, 18h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo