¿Convertir una cadena hexadecimal en un número entero de manera eficiente en C?

8 minutos de lectura

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

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

avatar de usuario
Patricio

Usted quiere strtol o strtoul. Véase también el página del manual de Unix

avatar de usuario
orwellófilo

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

La pregunta era “la forma más eficiente”. El OP no especifica la plataforma, podría estar compilando para 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 deslumbrantemente rápido. Maneja mayúsculas, minúsculas, caracteres no válidos, entrada hexadecimal de tamaño impar (por ejemplo: 0xfff) y el tamaño máximo está limitado solo por el compilador.

Para compiladores que no sean GCC o C++ o compiladores que no acepten la elegante declaración hexadecimal.

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

  • ¿Tengo razón al pensar en el hextable el código de inicialización es un pseudocódigo (si es así, vale la pena señalarlo), ¿o es una sintaxis de inicialización de matriz esotérica con la que no estoy familiarizado?

    – John Carter

    7 de noviembre de 2012 a las 1:02

  • No está compilando con Android ndk-build.

    – hB0

    8 de noviembre de 2013 a las 22:53

  • @ hB0 responderé a esa observación increíblemente vaga y sin sentido respondiendo del mismo modo: se compila bien en sonido metálico. hay 22 advertencias, pero eso es de esperar.

    – Orwellófilo

    17 de noviembre de 2013 a las 14:45

  • Usé la herramienta ndk-build en android ndk – desarrollador.android.com/tools/sdk/ndk/index.html y no compila me da un error específicamente en la declaración de la matriz. Aunque me encanta el fragmento de código, pero no pude usarlo, tuve que usar otro método bueno (pero ineficiente). No puedo darte el error de compilación exacto ahora… (ya te di +1 la última vez)

    – hB0

    19 de noviembre de 2013 a las 10:12


  • @hB0 solo comenta la segunda línea de código con “[0..255]” en él, y reza para que nunca te pasen una entrada no válida

    – Orwellófilo

    20 de noviembre de 2013 a las 12:38

avatar de usuario
marca harrison

Prueba esto:

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

  • Es brillante. Nunca había visto este método antes.

    – Nube Cho

    20 de diciembre de 2017 a las 21:32

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 AF en mayúsculas. No funciona si len está más allá de su 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, incluidos los 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);

Saldrá:
ingrese la descripción de la imagen aquí

  • No lo creo, pero tal vez se olvidó de proporcionar algunos argumentos.

    – Radhoo

    17 mayo 2017 a las 18:38

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

Verá, no existe tal cosa como “valor hexadecimal” y “valor decimal” (o “número hexadecimal” y “número decimal”). “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 son 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 usar una representación entera como intermedia: primero, convertir la representación hexadecimal ASCII en un número entero de tamaño suficiente (usando funciones de strto... grupo, como strtol), luego convierta el entero a la representación decimal ASCII (usando sprintf).

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

  • No lo creo, pero tal vez se olvidó de proporcionar algunos argumentos.

    – Radhoo

    17 mayo 2017 a las 18:38

avatar de usuario
Comunidad

@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 debajo del capó.

Realmente no creo que su solución debería haber sido rechazada, pero mi suposición de por qué está sucediendo es porque es menos práctica. La idea de votar es que la “mejor” respuesta flotará en la parte superior, y aunque su respuesta puede ser más instructiva sobre lo que sucede debajo del 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.

Una vez más, no creo que haya nada de malo en su respuesta desde un punto de vista educativo, y ciertamente no la votaría (y no lo hice). No se desanime y deje de publicar solo porque a algunas personas no les gustó una de sus respuestas. Sucede.

Dudo que mi respuesta te haga sentir mejor acerca de que la tuya haya sido rechazada, pero sé que no es especialmente divertido cuando preguntas por qué algo está siendo rechazado y nadie responde.

  • En agosto de 2008, el sitio era completamente nuevo y los comentarios no fueron implementados.

    – Parque Derek

    29/10/2010 a las 20:38

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad