Domanda

In C, qual è il modo più efficiente per convertire una stringa di cifre esadecimali in un binario unsigned int O unsigned long?

Ad esempio, se ho 0xFFFFFFFE, voglio un int con il valore base10 4294967294.

È stato utile?

Soluzione

Tu vuoi strtol O strtoul.Vedi anche il Pagina man di Unix

Altri suggerimenti

Modificare: Ora compatibile con compilatori MSVC, C++ e non GNU (vedi fine).

La domanda era "il modo più efficiente". L'OP non specifica la piattaforma, potrebbe compilare per un chip Atmel basato su RISC con 256 byte di archiviazione flash per il suo codice.

Per la cronaca, e per quelli (come me), che apprezzano la differenza tra "il modo più semplice" e il "modo più efficiente" e a cui piace imparare...

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; 
}

Non richiede librerie esterne e dovrebbe essere incredibilmente veloce.Gestisce caratteri maiuscoli, minuscoli, non validi, input esadecimali di dimensioni dispari (ad esempio:0xfff) e la dimensione massima è limitata solo dal compilatore.

Per compilatori o compilatori non GCC o C++ che non accettano la fantasiosa dichiarazione esadecimale.

Sostituisci la prima istruzione con questa versione (più lunga, ma più 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
};

Prova questo:

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

Se non hai stdlib devi farlo manualmente.

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;
}

Nota:Questo codice presuppone la maiuscola A-F.Non funziona se len supera il numero intero più lungo di 32 o 64 bit e non viene rilevato alcun errore per i caratteri esadecimali illegali.

Per i microcontrollori AVR ho scritto la seguente funzione, inclusi i commenti pertinenti per facilitarne la comprensione:

/**
 * 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;
}

Esempio:

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

Verrà prodotto:enter image description here

Come spesso accade, la tua domanda soffre di un grave errore/ambiguità terminologica.Nel linguaggio comune di solito non ha importanza, ma nel contesto di questo specifico problema è di fondamentale importanza.

Vedi, non esistono "valore esadecimale" e "valore decimale" (o "numero esadecimale" e "numero decimale")."Hex" e "decimal" sono proprietà di rappresentazioni di valori.Nel frattempo, i valori (o numeri) di per sé non hanno alcuna rappresentazione, quindi non possono essere "esadecimali" o "decimali".Per esempio, 0xF E 15 nella sintassi C sono due diversi rappresentazioni Di lo stesso numero.

Immagino che la tua domanda, nel modo in cui è formulata, suggerisca che è necessario convertire la rappresentazione esadecimale ASCII di un valore (ad es.una stringa) in una rappresentazione decimale ASCII di un valore (un'altra stringa).Un modo per farlo è utilizzare una rappresentazione intera come intermedia:innanzitutto, convertire la rappresentazione esadecimale ASCII in un numero intero di dimensioni sufficienti (utilizzando le funzioni from strto... gruppo, come strtol), quindi convertire il numero intero nella rappresentazione decimale ASCII (utilizzando sprintf).

Se non è quello che devi fare, allora devi chiarire la tua domanda, poiché è impossibile capirlo dal modo in cui è formulata.

@Eric

Perché una soluzione di codice che funziona viene bocciata?Certo, è brutto e potrebbe non essere il modo più veloce per farlo, ma è più istruttivo che dire "strtol" o "sscanf".Se lo provi tu stesso, imparerai qualcosa su come accadono le cose sotto il cofano.

Non penso davvero che la tua soluzione avrebbe dovuto essere respinta, ma la mia ipotesi sul motivo per cui sta accadendo è perché è meno pratica.L'idea con il voto è che la risposta "migliore" fluttua in cima e, sebbene la tua risposta possa essere più istruttiva su ciò che accade sotto il cofano (o su come potrebbe accadere), non è sicuramente il modo migliore per analizzare i numeri esadecimali in un sistema produttivo.

Ancora una volta, non penso che ci sia qualcosa di sbagliato nella tua risposta da un punto di vista educativo, e certamente non la voterei (e non l'ho fatto).Non scoraggiarti e non smettere di pubblicare solo perché ad alcune persone non è piaciuta una delle tue risposte.Succede.

Dubito che la mia risposta ti faccia sentire meglio riguardo alla tua bocciatura, ma so che non è particolarmente divertente quando chiedi perché qualcosa viene bocciato e nessuno risponde.

Per stringhe esadecimali più grandi come nell'esempio che dovevo usare strtoul.

Da esadecimale a decimale.Non eseguirlo su compilatori online, perché non funzionerà.

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

Perché una soluzione di codice che funziona viene votata?Certo, è brutto ...

Forse perché oltre ad essere brutto non è educativo e no lavoro.Inoltre, sospetto che, come me, la maggior parte delle persone non abbia il potere di modificare al momento (e, a giudicare dal grado necessario, non lo avrà mai).

L'uso di un array può essere utile per l'efficienza, ma non è menzionato in questo codice.Inoltre non tiene conto delle lettere maiuscole e minuscole, quindi non funziona per l'esempio fornito nella domanda.FFFFFFFE

@Eric

In realtà speravo di vedere una procedura guidata del C pubblicare qualcosa di veramente interessante, un po' come quello che ho fatto io ma meno dettagliato, pur continuando a farlo "manualmente".

Beh, non sono un guru del C, ma ecco cosa mi è venuto in mente:

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;
}

Inizialmente avevo più bitmasking in corso invece di confronti, ma dubito seriamente che il bitmasking sia più veloce del confronto sull'hardware moderno.

Prova questo per convertire da decimale a esadecimale

    #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);
}

In C puoi convertire un numero esadecimale in decimale in molti modi.Un modo è convertire il numero esadecimale in un numero intero.Personalmente ho trovato questo semplice e piccolo.

Ecco un codice di esempio per convertire un numero esadecimale in un numero decimale con l'aiuto del 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;
}

Attualmente funziona solo con le lettere minuscole, ma è semplicissimo farlo funzionare con entrambi.

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";
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top