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 :

Convertir un décimal en hexa


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 140
    Par défaut Convertir un décimal en hexa
    Bonjour,

    Je viens de coder une fonction qui permet de convertir un décimal en hexadécimal. Je l'ai fait pour tout nombre de type unsigned int, sachant qu'en fait le plus grand nombre qui sera passé à ma fonction ne dépassera pas la valeur décimale du dernier caractère de la table ASCII étendue, soit 255 ( besoin de cette fonction pour écrire des données en hexa dans le registre ).

    La voici :

    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    char *conversion_HEXA(unsigned int i)
    {
        char *res = NULL;
        int r = 0;
        int q = 0;
        int taille = 0;
     
        q = i / 16;
        taille++;
     
        do
        {
            q /= 16;
            taille++;
     
        }while (q != 0);
     
        if ((res = malloc(taille)) == NULL)
        {
            printf("Erreur d'allocation mémoire...\n");
        }
     
        r = i % 16;
        q = i / 16;
     
        res[taille] = '\0';
        taille--;
     
        if (r == 10)
                res[taille] = 65;
            else if (r == 11)
                res[taille] = 66;
            else if (r == 12)
                res[taille] = 67;
            else if (r == 13)
                res[taille] = 68;
            else if (r == 14)
                res[taille] = 69;
            else if (r == 15)
                res[taille] = 70;
            else if (r == 16)
                res[taille] = 71;
            else
                res[taille] = 48+r;
     
        do
        {
            taille--;
     
            r = q % 16;
            q /= 16;
     
            if (r == 10)
                res[taille] = 65;
            else if (r == 11)
                res[taille] = 66;
            else if (r == 12)
                res[taille] = 67;
            else if (r == 13)
                res[taille] = 68;
            else if (r == 14)
                res[taille] = 69;
            else if (r == 15)
                res[taille] = 70;
            else if (r == 16)
                res[taille] = 71;
            else
                res[taille] = 48+r;
     
        }while (q != 0);
     
        return(res);
    }
     
    int main ()
    {
        char *tab = NULL;
     
        printf("%s\n", tab = conversion_HEXA(1000));
     
        return(0);
    }
    J'aurais aimé avoir vos commentaires et avis sur ce bout de code : est-ce bien codé ? Peut-on faire plus simple ?

    J'aimerais un retour critique dessus.

    Merci par avance.


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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    C'est mal codé: Tu devrais utiliser les constantes caractères au lieu des codes ASCII.
    De plus, je déconseille l'allocation dynamique pour ça, utilise plutôt un buffer passé en paramètre. Surtout que dans ton exemple de code, il y a une fuite mémoire.

    Ensuite, il y a abus de langage: Tu ne convertis pas "un décimal" en hexadécimal, tu exprimes un nombre en notation hexadécimale. Et tes chaînes de if() sont inutilement compliquées, alors que les caractères A à F sont alignés même en EBCDIC...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 140
    Par défaut
    Merci pour ta réponse Médinoc.

    Tu devrais utiliser les constantes caractères au lieu des codes ASCII.
    Ceux que je passe en paramètre de la fonction, c'est bien ça ? C'est ce qui est prévu, là c'est juste un exemple généraliste.

    De plus, je déconseille l'allocation dynamique pour ça, utilise plutôt un buffer passé en paramètre. Surtout que dans ton exemple de code, il y a une fuite mémoire.
    Comment connaître la taille du buffer à l'avance ? (bon ok, pour mon besoin, le buffer aura toujours une taille de 3, donc oui je peux effectivement simplifier) Mais dans le cas général, on ferait comment ?

    Surtout que dans ton exemple de code, il y a une fuite mémoire.
    Pourrais-tu m'en dire plus ?

    Et tes chaînes de if() sont inutilement compliquées, alors que les caractères A à F sont alignés même en EBCDIC...
    Ah oui, j'y avais pas pensé, merci.


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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Je conseille plutôt un truc de ce genre:
    Code C : 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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include <limits.h>
    #include <string.h>
     
    /* (c) Eric Sosman 2001 */
    #define BIG_ENOUGH (1 + (sizeof(long long) * CHAR_BIT + 2) / 3 + 1)
     
    /*(c) Medinoc 2009 */
    int formatInt(
     char *sortie,     /*[out] Doit faire au moins BIG_ENOUGH caractères. */
     long long nombre, /*[in] Nombre à formater. */
     int base          /*[in] Base du nombre, entre 2 et 36. */
     ) /* Retourne 0 si OK, -1 si erreur. */
    {
    	static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    	char buffer[BIG_ENOUGH];
    	size_t i=BIG_ENOUGH;
    	int bPremier = 1;
     
    	if(base < 2 || base > 36 || sortie==NULL)
    		return -1;
     
    	/*Place un caractère nul à la fin du buffer interne.*/
    	buffer[--i] = '\0';
     
    	/*Remplit le buffer interne en partant de la fin.*/
    	while(bPremier || nombre!=0)
    	{
    		bPremier = 0;
    		buffer[--i] = digits[ nombre%base ];
    		nombre /= base;
    	}
    	/*Recopie vers le buffer de sortie.*/
    	strcpy(sortie, buffer+i);
    	return 0;
    }
    En étant un peu plus téméraire, on pourrait même se passer du buffer interne: Écrire directement sur la sortie et décaler au début par un memmove().
    Et quand j'ai vraiment besoin de performance, j'ai une fonction qui ne fait même pas de décalage, et retourne un pointeur sur la fin du buffer à la place.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Pourrais-tu m'en dire plus ?
    Tu oublies le free() sur tab. De plus, beaucoup de gens oublieraient tab aussi au passage, passant directement le résultat de la fonction à printf().
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 140
    Par défaut
    Ah vi, j'oublie systématiquement le free pour libérer la mémoire dans mes programmes, je vais tout reprendre et rectifier ça, j'ai oublié. Merci pour cette importante remarque.

    Écrire directement sur la sortie et décaler au début par un memmove().
    Je ne suis pas familier avec ces fonctions, il faudrait que je m'y mette.

    Et quand j'ai vraiment besoin de performance, j'ai une fonction qui ne fait même pas de décalage, et retourne un pointeur sur la fin du buffer à la place.
    Ah vi...

    Merci pour ton bout de code et tes remarques, je vais prendre tout cela en compte et aussi reprendre l'ensemble du code de mon command line tool afin de libérer la mémoire.


  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 140
    Par défaut
    J'aurais deux dernières questions, sinon j'ai tout compris

    1) #define BIG_ENOUGH (1 + (sizeof(long long) * CHAR_BIT + 2) / 3 + 1)

    => Pourrais-tu m'expliquer cette ligne ? J'ai un peu du mal à comprendre comment cette constante est définie.

    2) while(bPremier || nombre!=0)

    => Je ne saisis pas l'utilité de la constante bPremier.

    Merci.

  8. #8
    Membre Expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Par défaut
    pourquoi ne pas utiliser sprintf?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    char maString[9];
    unsigned int  i  = 15558;
     
    sprintf(maString,"%x", i)
    // ou
    sprintf(maString,"%X", i)
    maintenant un octet = 2 digits en hexa, donc un entier sur 4 octets fait ....?

  9. #9
    Membre Expert Avatar de jabbounet
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juin 2009
    Messages
    1 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 909
    Par défaut
    et cette solution ne conviens pas?

    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
    22
    23
    24
    25
    26
    27
    28
    #include <stdlib.h>
    #include <stdio.h>
     
    static char * dec2hex(unsigned int data) {
     
      char * hData = malloc(sizeof(char)*9);
      if (hData == NULL) {
        perror("malloc");
      }
     
      sprintf(hData,"%08X",data);
      hData[8] = 0;
     
      return hData;
    }
     
    int main(int argc, char ** argv) {
     
      char * s;
      unsigned int  i;
     
      for (i = 0; i < 500; i++) {
        s = dec2hex(i*50000);
        printf(" %11d --Hex--> %s\n",i*50000,s); 
        free(s);
      }
      return 0; 
    }

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 140
    Par défaut
    J'obtiens finalement ça ( le but est d'obtenir le nombre hexadécimal d'un caractère ) :
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    #include <stdio.h>
    #include <windows.h>
     
    char *conv_ascii_hexa(unsigned char c);
     
    char *conv_ascii_hexa(unsigned char c)
    {
        char *res = NULL;
        static const char digits[] = "0123456789ABCDEF";
        unsigned int quotient = c;
        int size = 0;
     
        do
        {
            quotient /= 16;
            size++;
     
        }while (quotient != 0);
     
        if ((res = malloc(size)) == NULL)
        {
            printf("Erreur d'allocation mémoire...\n");
        }
     
        res[size] = '\0';
        quotient = c;
     
        do
        {
            size--;
            res[size] = digits[quotient % 16];
            quotient /= 16;
     
        }while (quotient != 0);
     
        return(res);
    }
     
    int main ()
    {
        char *tab = NULL;
     
        printf("%s\n", tab = conv_ascii_hexa('¨'));
        free(tab);
        (char*)tab = NULL;
     
        return(0);
    }
    Ce n'est pas encore tout à fait "parfait" je pense, mais c'est déjà mieux et j'ai essayé de prendre en compte tous vos conseils.


  11. #11
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Citation Envoyé par Merillym Voir le message
    J'obtiens finalement ça ( le but est d'obtenir le nombre hexadécimal d'un caractère ) :
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    #include <stdio.h>
    #include <windows.h>
     
    char *conv_ascii_hexa(unsigned char c);
     
    char *conv_ascii_hexa(unsigned char c)
    {
        char *res = NULL;
        static const char digits[] = "0123456789ABCDEF";
        unsigned int quotient = c;
        int size = 0;
     
        do
        {
            quotient /= 16;
            size++;
     
        }while (quotient != 0);
     
        if ((res = malloc(size)) == NULL)
        {
            printf("Erreur d'allocation mémoire...\n");
        }
     
        res[size] = '\0';
        quotient = c;
     
        do
        {
            size--;
            res[size] = digits[quotient % 16];
            quotient /= 16;
     
        }while (quotient != 0);
     
        return(res);
    }
     
    int main ()
    {
        char *tab = NULL;
     
        printf("%s\n", tab = conv_ascii_hexa('¨'));
        free(tab);
        (char*)tab = NULL;
     
        return(0);
    }
    Ce n'est pas encore tout à fait "parfait" je pense, mais c'est déjà mieux et j'ai essayé de prendre en compte tous vos conseils.

    Non dans ce cas là, mieux vaut que tu restes sur ma solution.

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 140
    Par défaut
    Oui mais la tienne prend des arguments de type unsigned int alors que les arguments qui seront passés à ma fonction seront de type unsigned char... C'est pour ça que je n'ai pas pris la tienne.

    Mais il est fort possible que quelque chose m'échappe

    edit: Enfin ça doit revenir au même en fait.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Aussi, le cast sur tab ne sert à rien.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 140
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Aussi, le cast sur tab ne sert à rien.
    C'était un warning du compilo, mais c'est bien ce qu'il me semblait. Je compile en C.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Convertir chaine "0x12" en hexa
    Par lilou77 dans le forum C++
    Réponses: 4
    Dernier message: 26/06/2007, 15h54
  2. [PHP-JS] Convertir en décimal
    Par MayOL69bg dans le forum Langage
    Réponses: 2
    Dernier message: 20/04/2007, 19h47
  3. cherche code pour convertir un décimal en base 35
    Par coufcouf dans le forum Langage
    Réponses: 2
    Dernier message: 05/03/2007, 15h44
  4. Convertir un décimal en binaire
    Par rouliane dans le forum C++
    Réponses: 4
    Dernier message: 14/12/2006, 16h15
  5. Réponses: 4
    Dernier message: 21/12/2005, 12h20

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