Question

En C, quel est le moyen le plus efficace de convertir une chaîne de chiffres hexadécimaux en binaire unsigned int ou unsigned long?

Par exemple, si j'ai 0xFFFFFFFE, je veux un int avec la valeur base10 4294967294.

Était-ce utile?

La solution

Tu veux strtol ou strtoul.Voir aussi le Page de manuel Unix

Autres conseils

Modifier: Désormais compatible avec les compilateurs MSVC, C++ et non-GNU (voir fin).

La question était «le moyen le plus efficace». L'OP ne spécifie pas la plate-forme, il pourrait compiler pour une puce atmel basée sur RISC avec 256 octets de stockage flash pour son code.

Pour mémoire, et pour ceux (comme moi), qui apprécient la différence entre « la manière la plus simple » et la « manière la plus efficace », et qui aiment apprendre…

static const long hextable[] = {
   [0 ... 255] = -1, // bit aligned access into this table is considerably
   ['0'] = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // faster for most modern processors,
   ['A'] = 10, 11, 12, 13, 14, 15,       // for the space conscious, reduce to
   ['a'] = 10, 11, 12, 13, 14, 15        // signed char.
};

/** 
 * @brief convert a hexidecimal string to a signed long
 * will not produce or process negative numbers except 
 * to signal error.
 * 
 * @param hex without decoration, case insensitive. 
 * 
 * @return -1 on error, or result (max (sizeof(long)*8)-1 bits)
 */
long hexdec(unsigned const char *hex) {
   long ret = 0; 
   while (*hex && ret >= 0) {
      ret = (ret << 4) | hextable[*hex++];
   }
   return ret; 
}

Il ne nécessite aucune bibliothèque externe et doit être incroyablement rapide.Il gère les majuscules, les minuscules, les caractères invalides et les entrées hexadécimales de taille impaire (par exemple :0xfff), et la taille maximale n'est limitée que par le compilateur.

Pour les compilateurs non-GCC ou C++ ou les compilateurs qui n'accepteront pas la déclaration hextable sophistiquée.

Remplacez la première instruction par cette version (plus longue, mais plus conforme) :

static const long hextable[] = { 
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};

Essaye ça:

#include <stdio.h>
int main()
{
    char s[] = "fffffffe";
    int x;
    sscanf(s, "%x", &x);
    printf("%u\n", x);
}

Si vous n'avez pas stdlib, vous devez le faire manuellement.

unsigned long hex2int(char *a, unsigned int len)
{
    int i;
    unsigned long val = 0;

    for(i=0;i<len;i++)
       if(a[i] <= 57)
        val += (a[i]-48)*(1<<(4*(len-1-i)));
       else
        val += (a[i]-55)*(1<<(4*(len-1-i)));

    return val;
}

Note:Ce code suppose A-F majuscule.Cela ne fonctionne pas si len dépasse votre entier le plus long de 32 ou 64 bits, et il n'y a pas de détection d'erreurs pour les caractères hexadécimaux illégaux.

Pour les microcontrôleurs AVR, j'ai écrit la fonction suivante, y compris des commentaires pertinents pour la rendre facile à comprendre :

/**
 * hex2int
 * take a hex string and convert it to a 32bit number (max 8 hex digits)
 */
uint32_t hex2int(char *hex) {
    uint32_t val = 0;
    while (*hex) {
        // get current character then increment
        char byte = *hex++; 
        // transform hex character to the 4bit equivalent number, using the ascii table indexes
        if (byte >= '0' && byte <= '9') byte = byte - '0';
        else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
        else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;    
        // shift 4 to make space for new digit, and add the 4 bits of the new digit 
        val = (val << 4) | (byte & 0xF);
    }
    return val;
}

Exemple:

char *z ="82ABC1EF";
uint32_t x = hex2int(z);
printf("Number is [%X]\n", x);

Affichera :enter image description here

Comme cela arrive souvent, votre question souffre d'une grave erreur/ambiguïté terminologique.Dans le langage courant, cela n’a généralement pas d’importance, mais dans le contexte de ce problème spécifique, cela revêt une importance cruciale.

Vous voyez, il n’existe pas de « valeur hexadécimale » et de « valeur décimale » (ou de « nombre hexadécimal » et de « nombre décimal »)."Hex" et "decimal" sont des propriétés de représentations de valeurs.Pendant ce temps, les valeurs (ou les nombres) en eux-mêmes n'ont aucune représentation, ils ne peuvent donc pas être « hexadécimaux » ou « décimaux ».Par exemple, 0xF et 15 dans la syntaxe C sont deux différents représentations de le même numéro.

Je suppose que votre question, telle qu'elle est formulée, suggère que vous devez convertir la représentation hexadécimale ASCII d'une valeur (c'est-à-direune chaîne) en une représentation décimale ASCII d'une valeur (une autre chaîne).Une façon de procéder consiste à utiliser une représentation entière comme représentation intermédiaire :Tout d'abord, convertissez la représentation hexadécimale ASCII en un entier de taille suffisante (en utilisant les fonctions de strto... groupe, comme strtol), puis convertissez l'entier en représentation décimale ASCII (en utilisant sprintf).

Si ce n'est pas ce que vous devez faire, vous devez alors clarifier votre question, car il est impossible de la comprendre à partir de la façon dont votre question est formulée.

@Éric

Pourquoi une solution de code qui fonctionne est-elle rejetée ?Bien sûr, c'est moche et ce n'est peut-être pas le moyen le plus rapide de le faire, mais c'est plus instructif que de dire « strtol » ou « sscanf ».Si vous l’essayez vous-même, vous apprendrez quelque chose sur la façon dont les choses se passent sous le capot.

Je ne pense pas vraiment que votre solution aurait dû être rejetée, mais je suppose que cela se produit parce qu'elle est moins pratique.L'idée du vote est que la "meilleure" réponse flottera vers le haut, et bien que votre réponse puisse être plus instructive sur ce qui se passe sous le capot (ou sur la manière dont cela pourrait se produire), ce n'est certainement pas la meilleure façon d'analyser les nombres hexadécimaux. dans un système de production.

Encore une fois, je ne pense pas qu'il y ait quelque chose de mal dans votre réponse d'un point de vue pédagogique, et je ne la rejetterais certainement pas (et je ne l'ai pas fait).Ne vous découragez pas et arrêtez de publier simplement parce que certaines personnes n'ont pas aimé l'une de vos réponses.Ça arrive.

Je doute que ma réponse vous fasse vous sentir mieux à l'idée que la vôtre ait été rejetée, mais je sais que ce n'est particulièrement pas amusant lorsque vous demandez pourquoi quelque chose a été rejeté et personne ne répond.

Pour les chaînes Hex plus grandes comme dans l'exemple que je devais utiliser strtoul.

Hexadécimal à décimal.Ne l'exécutez pas sur des compilateurs en ligne, car cela ne fonctionnera pas.

#include<stdio.h>
void main()
{
    unsigned int i;
    scanf("%x",&i);
    printf("%d",i);
}

Pourquoi une solution de code qui fonctionne est-elle votée?Bien sûr, c'est moche ...

Peut-être parce qu'en plus d'être laid, ce n'est pas éducatif et n'a pas travail.De plus, je soupçonne que comme moi, la plupart des gens n'ont pas le pouvoir de modifier à l'heure actuelle (et à en juger par le rang nécessaire, ils ne le feront jamais).

L'utilisation d'un tableau peut être bénéfique pour l'efficacité, mais cela n'est pas mentionné dans ce code.Il ne prend pas non plus en compte les majuscules et les minuscules, donc cela ne fonctionne pas pour l'exemple fourni dans la question.FFFFFFFE

@Éric

J'espérais en fait voir un assistant C publier quelque chose de vraiment cool, un peu comme ce que j'ai fait mais en moins verbeux, tout en le faisant "manuellement".

Eh bien, je ne suis pas un gourou du C, mais voici ce que j'ai trouvé :

unsigned int parseHex(const char * str)
{
    unsigned int val = 0;
    char c;

    while(c = *str++)
    {
        val <<= 4;

        if (c >= '0' && c <= '9')
        {
            val += c & 0x0F;
            continue;
        }

        c &= 0xDF;
        if (c >= 'A' && c <= 'F')
        {
            val += (c & 0x07) + 9;
            continue;
        }

        errno = EINVAL;
        return 0;
    }

    return val;
}

À l'origine, j'avais plus de masquage de bits au lieu de comparaisons, mais je doute sérieusement que le masquage de bits soit plus rapide que la comparaison sur du matériel moderne.

Essayez ceci pour convertir de décimal en hexadécimal

    #include<stdio.h>
    #include<conio.h>

    int main(void)
    {
      int count=0,digit,n,i=0;
      int hex[5];
      clrscr();
      printf("enter a number   ");
      scanf("%d",&n);

      if(n<10)
      {
          printf("%d",n);
      }

      switch(n)
      {
          case 10:
              printf("A");
            break;
          case 11:
              printf("B");
            break;
          case 12:
              printf("B");
            break;
          case 13:
              printf("C");
            break;
          case 14:
              printf("D");
            break;
          case 15:
              printf("E");
            break;
          case 16:
              printf("F");
            break;
          default:;
       }

       while(n>16)
       {
          digit=n%16;
          hex[i]=digit;
          i++;
          count++;
          n=n/16;
       }

       hex[i]=n;

       for(i=count;i>=0;i--)
       {
          switch(hex[i])
          {
             case 10:
                 printf("A");
               break;
             case 11:
                 printf("B");
               break;
             case 12:
                 printf("C");
               break;
             case  13:
                 printf("D");
               break;
             case 14:
                 printf("E");
               break;
             case 15:
                 printf("F");
               break;
             default:
                 printf("%d",hex[i]);
          }
    }

    getch();

    return 0;
}
#include "math.h"
#include "stdio.h"
///////////////////////////////////////////////////////////////
//  The bits arg represents the bit say:8,16,32...                                                                                                              
/////////////////////////////////////////////////////////////
volatile long Hex_To_Int(long Hex,char bits)
{
    long Hex_2_Int;
    char byte;
    Hex_2_Int=0;

    for(byte=0;byte<bits;byte++)
    {
        if(Hex&(0x0001<<byte))
            Hex_2_Int+=1*(pow(2,byte));
        else
            Hex_2_Int+=0*(pow(2,byte));
    }

    return Hex_2_Int;
}
///////////////////////////////////////////////////////////////
//                                                                                                                  
/////////////////////////////////////////////////////////////

void main (void)
{
    int Dec;   
    char Hex=0xFA;
    Dec= Hex_To_Int(Hex,8);  //convert an 8-bis hexadecimal value to a number in base 10
    printf("the number is %d",Dec);
}

En C, vous pouvez convertir un nombre hexadécimal en nombre décimal de plusieurs manières.Une solution consiste à convertir le nombre hexadécimal en un nombre entier.Personnellement, j'ai trouvé cela simple et petit.

Voici un exemple de code pour convertir un nombre hexadécimal en nombre décimal à l'aide du casting.

#include <stdio.h>

int main(){
    unsigned char Hexadecimal = 0x6D;   //example hex number
    int Decimal = 0;    //decimal number initialized to 0


        Decimal = (int) Hexadecimal;  //conversion

    printf("The decimal number is %d\n", Decimal);  //output
    return 0;
}

Cela ne fonctionne actuellement qu'avec les minuscules, mais il est très facile de le faire fonctionner avec les deux.

cout << "\nEnter a hexadecimal number: ";
cin >> hexNumber;
orighex = hexNumber;

strlength = hexNumber.length();

for (i=0;i<strlength;i++)
{
    hexa = hexNumber.substr(i,1);
    if ((hexa>="0") && (hexa<="9"))
    {
        //cout << "This is a numerical value.\n";
    }
    else
    {
        //cout << "This is a alpabetical value.\n";
        if (hexa=="a"){hexa="10";}
        else if (hexa=="b"){hexa="11";}
        else if (hexa=="c"){hexa="12";}
        else if (hexa=="d"){hexa="13";}
        else if (hexa=="e"){hexa="14";}
        else if (hexa=="f"){hexa="15";}
        else{cout << "INVALID ENTRY! ANSWER WONT BE CORRECT\n";}
    }
    //convert from string to integer

    hx = atoi(hexa.c_str());
    finalhex = finalhex + (hx*pow(16.0,strlength-i-1));
}
cout << "The hexadecimal number: " << orighex << " is " << finalhex << " in decimal.\n";
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top