Pregunta

En C, ¿cuál es la forma más eficiente de convertir una cadena de dígitos hexadecimales en binario? unsigned int o unsigned long?

Por ejemplo, si tengo 0xFFFFFFFE, quiero un int con el valor base10 4294967294.

¿Fue útil?

Solución

Quieres strtol o strtoul.Ver también el página de manual de Unix

Otros consejos

Editar: Ahora compatible con compiladores MSVC, C++ y no GNU (ver final).

La pregunta era "la manera más eficiente". El OP no especifica la plataforma, podría estar compilando un chip Atmel basado en RISC con 256 bytes de almacenamiento flash para su código.

Para que conste, y para aquellos (como yo), que aprecian la diferencia entre "la forma más fácil" y la "forma más eficiente", y que disfrutan aprendiendo...

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

No requiere bibliotecas externas y debería ser increíblemente rápido.Maneja mayúsculas, minúsculas, caracteres no válidos y entradas hexadecimales de tamaño impar (por ejemplo:0xfff), y el tamaño máximo está limitado únicamente por el compilador.

Para compiladores que no sean GCC o C++ o compiladores que no acepten la sofisticada declaración hextable.

Reemplace la primera declaración con esta versión (más larga, pero más 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
};

Prueba esto:

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

Si no tiene stdlib, debe hacerlo 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:Este código asume mayúsculas A-F.No funciona si len supera el entero más largo de 32 o 64 bits y no hay captura de errores para caracteres hexadecimales ilegales.

Para los microcontroladores AVR escribí la siguiente función, incluyendo comentarios relevantes para que sea fácil de entender:

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

Ejemplo:

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

Salida:enter image description here

Como suele suceder, su pregunta adolece de un grave error/ambigüedad terminológica.En el habla común normalmente no importa, pero en el contexto de este problema específico es de vital importancia.

Verá, no existen los "valores hexadecimales" y los "valores decimales" (o "números hexadecimales" y "números decimales")."Hex" y "decimal" son propiedades de representaciones de valores.Mientras tanto, los valores (o números) por sí mismos no tienen representación, por lo que no pueden ser "hexadecimales" o "decimales".Por ejemplo, 0xF y 15 en la sintaxis C hay dos diferentes representaciones de el mismo numero.

Supongo que su pregunta, tal como está planteada, sugiere que necesita convertir la representación hexadecimal ASCII de un valor (es decir,una cadena) en una representación decimal ASCII de un valor (otra cadena).Una forma de hacerlo es utilizar una representación entera como intermedia:Primero, convierta la representación hexadecimal ASCII a un número entero de tamaño suficiente (usando funciones de strto... grupo, como strtol), luego convierta el número entero en la representación decimal ASCII (usando sprintf).

Si eso no es lo que necesita hacer, entonces debe aclarar su pregunta, ya que es imposible descifrarla por la forma en que está formulada.

@eric

¿Por qué se rechaza una solución de código que funciona?Claro, es feo y puede que no sea la forma más rápida de hacerlo, pero es más instructivo que decir "strtol" o "sscanf".Si lo prueba usted mismo, aprenderá algo sobre cómo suceden las cosas bajo el capó.

Realmente no creo que su solución debería haber sido rechazada, pero supongo que por qué está sucediendo es porque es menos práctica.La idea de la votación es que la "mejor" respuesta flotará hacia la parte superior, y si bien su respuesta puede ser más instructiva sobre lo que sucede bajo el capó (o la forma en que podría suceder), definitivamente no es la mejor manera de analizar números hexadecimales. en un sistema de producción.

Nuevamente, no creo que haya nada malo en su respuesta desde un punto de vista educativo, y ciertamente no la rechazaría (ni la votaría).No te desanimes y dejes de publicar solo porque a algunas personas no les gustó una de tus respuestas.Sucede.

Dudo que mi respuesta te haga sentir mejor por el hecho de que la tuya haya sido rechazada, pero sé que no es especialmente divertido cuando preguntas por qué se rechaza algo y nadie responde.

Para cadenas Hex más grandes como en el ejemplo, necesitaba usar strtoul.

Hexadecimal a decimal.No lo ejecute en compiladores en línea porque no funcionará.

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

¿Por qué una solución de código que funciona a ser votada?Claro, es feo ...

Quizás porque además de feo no es educativo y no trabajar.Además, sospecho que, al igual que yo, la mayoría de las personas no tienen el poder de editar en este momento (y, a juzgar por el rango necesario, nunca lo tendrán).

El uso de una matriz puede ser bueno para la eficiencia, pero eso no se menciona en este código.Tampoco tiene en cuenta mayúsculas y minúsculas, por lo que no funciona para el ejemplo proporcionado en la pregunta.FFFFFFFE

@eric

De hecho, esperaba ver a un asistente de C publicar algo realmente interesante, algo así como lo que hice yo, pero menos detallado, y al mismo tiempo hacerlo "manualmente".

Bueno, no soy un gurú de C, pero esto es lo que se me ocurrió:

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

Originalmente tenía más enmascaramiento de bits en lugar de comparaciones, pero dudo seriamente que el enmascaramiento de bits sea más rápido que la comparación en hardware moderno.

Pruebe esto para convertir de decimal a hexadecimal

    #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 puedes convertir un número hexadecimal a decimal de muchas maneras.Una forma es convertir el número hexadecimal a un número entero.Personalmente encontré que esto es simple y pequeño.

Aquí hay un código de muestra para convertir un número hexadecimal en un número decimal con la ayuda de conversión.

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

Actualmente, esto solo funciona con minúsculas, pero es muy fácil hacerlo funcionar con ambas.

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";
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top