Método para convertir de Hex a Integer en C, ¡no puede aparecer en minúsculas!

StackOverflow https://stackoverflow.com/questions/1416571

  •  06-07-2019
  •  | 
  •  

Pregunta

Hola a todos, solo una cosa rápida, tengo el hexadecimal para el entero trabajando, pero necesito obtener los números en minúsculas. Esto es lo que tengo, ¿alguna idea para conseguir que la A a F sea insensible a mayúsculas y minúsculas?

int htoi(char f[]) {
    int  z, n;
    n = 0;

    for (z = 0; f[z] >= '0' && f[z] <= 'F'; ++z) 
        if (f[z] >= 'A' && f[z] <= 'F')
            n = 10 + 16 * n + (f[z] - 'A');
        else
            n = 16 * n + (f[z] - '0');
}

Probablemente sea algo pequeño, pero me gustaría incluir a-f y A-F. ¡Gracias por tu ayuda!

¿Fue útil?

Solución

Si estás haciendo esto para aprender cómo hacerlo, ignora esta publicación. Si está utilizando esta función porque necesita convertir una cadena de números hexadecimales a un int , debe dar un paseo en su biblioteca estándar. La función estándar strtol () convierte una cadena a un largo , que se puede convertir en un int (o un unsigned int mientras estaba en él). El tercer argumento es la base para convertir: en este caso, desearía una base 16 para hexadecimal. Además, si se le da la base 0, asumirá hexadecimal si la cadena comienza con 0x , octal si comienza con 0 y decimal de lo contrario. Es una función muy útil.


EDITAR: Acabo de notar esto, pero mientras estamos aquí, vale la pena mencionar que generalmente no debe usar un int para indexar las matrices. El estándar C define un tipo, llamado size_t , que está diseñado para almacenar índices de matriz. Generalmente es un unsigned int o unsigned long o algo así, pero se garantiza que será lo suficientemente grande como para almacenar cualquier matriz o desplazamiento de puntero que pueda usar.

El problema con el uso de solo un int es que, teóricamente, tal vez, algún día, alguien podría pasar una cadena más larga que INT_MAX , y luego su int se desbordará, probablemente se ajustará, y comenzará a leer la memoria, probablemente no debería porque está usando un índice negativo. Esto es muy poco probable, especialmente para una función como esta, porque el valor int que devuelve se desbordará mucho antes de que su contador int se desborde, pero es algo importante a tener en cuenta.

Para ser técnicamente correcto, solo debe usar las variables de tipo size_t para indexar las matrices, o al menos solo usar los tipos unsigned , a menos que realmente quiera intentar acceder a negativos elementos (que generalmente es una mala idea a menos que sepa lo que está haciendo). Sin embargo, no es un gran problema aquí.

Otros consejos

Cree otra función que convierta un dígito hexadecimal en un entero:

int hex_digit_to_integer(char digit) {
    if (digit >= 'A' && digit <= 'F') {
        return digit - 'A' + 10;
    } else if (digit >= 'a' && digit <= 'f') {
        return digit - 'a' + 10;
    } else if (digit >= '0' && digit <= '9') {
        return digit - '0';
    }

    return -1; // Bad input.
}

Observe cómo maneja cuatro casos:  * digit es una letra mayúscula A..F ,  * digit es una letra minúscula a..f ,  * digit es un dígito decimal 0..9 , y  * digit no es ninguno de los anteriores.

Ahora use la nueva función en su función original:

int htoi(char f[]) {
    int z, n;
    n = 0;

    /* Loop until we get something which isn't a digit (hex_digit_to_integer returns something < 0). */
    for (z=0; hex_digit_to_integer(f[z]) >= 0; ++z) {
        n = 16 * n + hex_digit_to_integer(f[z]);
    }
}

¿Observa cuánto más limpia se ve la nueva función?

Si eres aventurero, puedes usar esta función mágica (que no maneja entradas incorrectas, por lo que debes verificar eso de antemano):

int hex_digit_to_integer(char digit) {
    return digit - (digit & 64 ? 55 : 48) & 15;
}

Reemplace todo f [z] con una variable dedicada. Asigne esa variable con toupper (f [z])

Aquí hay un código del paquete NPS NSRL Bloom:

static int *hexcharvals = 0;

/** Initialization function is used solely for hex output
 */
static void nsrl_bloom_init()
{
    if(hexcharvals==0){
        /* Need to initialize this */
        int i;
        hexcharvals = calloc(sizeof(int),256);
        for(i=0;i<10;i++){
            hexcharvals['0'+i] = i;
        }
        for(i=10;i<16;i++){
            hexcharvals['A'+i-10] = i;
            hexcharvals['a'+i-10] = i;
        }
    }
}

/**
 * Convert a hex representation to binary, and return
 * the number of bits converted.
 * @param binbuf output buffer
 * @param binbuf_size size of output buffer in bytes.
 * @param hex    input buffer (in hex)
 */
int nsrl_hex2bin(unsigned char *binbuf,size_t binbuf_size,const char *hex)
{
    int bits = 0;
    if(hexcharvals==0) nsrl_bloom_init();
    while(hex[0] && hex[1] && binbuf_size>0){
        *binbuf++ = ((hexcharvals[(unsigned char)hex[0]]<<4) |
                     hexcharvals[(unsigned char)hex[1]]);
        hex  += 2;
        bits += 8;
        binbuf_size -= 1;
    }
    return bits;
}

Este código está diseñado para ser súper rápido, manejar hexágonos en mayúsculas y minúsculas, y manejar cadenas hexagonales de cualquier longitud. La función nsrl_hex2bin () toma un búfer binario, el tamaño de ese búfer y la cadena hexadecimal que desea convertir. Devuelve el número de bits que realmente se convirtieron.

Oh, si solo quieres un número entero, entonces puedes multiplicar los bytes (para el código independiente de endian), o simplemente hacer una conversión (para el código dependiente de endian).

Puede probar sscanf en su lugar:

#include <stdio.h>

...

//NOTE: buffer overflow if f is not terminated with \0 !!
int htoi(char f[]){
  int intval = -1;
  if (EOF == sscanf(f, "%x", &intval))
    return -1; //error
  return intval;
}

Dos opciones:

Convierta a mayúsculas antes de hacer su escaneo.

Agregue un segundo si está en el bucle cuatro que maneja minúsculas.

Pruebe esto en su lugar:

int htoi (char f[]) {
    int  z, n;
    n = 0;
    for (z = 0; f[z] != '\0'; ++z) { 
        if (f[z] >= '0' && f[z] <= '9') {
            n = n * 16 + f[z] - '0';
        } else {
            if (f[z] >= 'A' && f[z] <= 'F') {
                n = n * 16 + f[z] - 'A' + 10;
            } else {
                if (f[z] >= 'a' && f[z] <= 'f') {
                    n = n * 16 + f[z] - 'a' + 10;
                } else {
                    break;
                }
            }
        }
    }
    return n;
}

Todavía trata la entrada de la misma manera que la suya (solía usar punteros, pero a veces son difíciles de entender para un principiante), pero presenta tres casos separados, 0-9, AF y af, tratando cada uno de manera apropiada.

Su código original en realidad permitiría caracteres erróneos (los seis entre '9' y 'A') y produciría resultados incorrectos basados ??en ellos.

Tenga en cuenta que este nuevo código solo normalmente termina el ciclo al final de la cadena. Encontrar un carácter hexadecimal no válido saldrá del bucle, funcionalmente idéntico a su condición de terminación.

Use strtol () por favor. Esta es la función estándar C90 y mucho más potente que la mayoría de las implementaciones ingenuas. También es compatible con la conversión perfecta de dec (sin prefijo), hexadecimal (0x) y oct (comenzando con 0).

Y la implementación usando la rotación de turnos en lugar de la multiplicación.

int HexToDec(char *Number)
{

    unsigned int val = 0;

    int i , nibble;
    for(i = strlen( Number ) - 1; i >= 0; --i, nibble += 4)
    {
        const char hex = Number[i];
        if (hex >= '0' && hex <= '9')
            val += (hex - '0')<<nibble;
        else if (hex >= 'A' && hex <= 'F')
            val += (hex - 'A' + 10)<<nibble;
        else if (hex >= 'a' && hex <= 'f')
            val += (hex - 'a' + 10)<<nibble;
        else
            return -1;
    }
    return val;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top