Metodo per convertire da esadecimale a intero in C, non è possibile ottenere minuscole!

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

  •  06-07-2019
  •  | 
  •  

Domanda

Ciao a tutti, solo una cosa veloce, ho l'esagono che funziona a numeri interi, ma ho bisogno di mettere i numeri in minuscolo. Ecco cosa ho, qualche idea da ottenere per rendere insensibile il caso dalla A alla F?

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

Probabilmente solo una piccola cosa, ma mi piacerebbe includere a-f e A-F. Grazie per il tuo aiuto!

È stato utile?

Soluzione

Se lo stai facendo per imparare a farlo, ignora questo post. Se stai usando questa funzione perché devi convertire una stringa di numeri esadecimali in un int , dovresti fare una passeggiata nella tua libreria standard. La funzione standard strtol () converte una stringa a un long , che può essere convertito in un int (o un unsigned int mentre erano lì). Il terzo argomento è la base in cui convertire - in questo caso, si vorrebbe la base 16 per esadecimale. Inoltre, se viene fornita la base 0, assumerà esadecimale se la stringa inizia con 0x , ottale se inizia con 0 e decimale altrimenti. È una funzione molto utile.


EDIT: L'ho appena notato, ma mentre siamo qui, vale la pena ricordare che generalmente non dovresti usare un int per indicizzare le matrici. Lo standard C definisce un tipo, chiamato size_t , progettato per memorizzare indici di array. In genere è un unsigned int o unsigned long o qualcosa del genere, ma è garantito che sia abbastanza grande da memorizzare qualsiasi array o offset del puntatore che è possibile utilizzare.

Il problema con l'uso di solo un int è che, teoricamente, forse, un giorno, qualcuno potrebbe passare una stringa più lunga di INT_MAX , e quindi il tuo int traboccerà, probabilmente avvolgerà, e inizierà a leggere la memoria che probabilmente non dovrebbe perché sta usando un indice negativo. Questo è altamente improbabile, specialmente per una funzione come questa, perché il valore int che restituisci trabocca molto prima che il tuo contatore int trabocca, ma è una cosa importante da tenere a mente.

Per essere tecnicamente corretti, dovresti usare le variabili di tipo size_t solo per indicizzare gli array, o almeno usare solo i tipi non firmati , a meno che tu non voglia davvero provare ad accedere al negativo elementi (che di solito è una cattiva idea se non sai cosa stai facendo). Tuttavia, non è un grosso problema qui.

Altri suggerimenti

Crea un'altra funzione che trasforma una cifra esadecimale in un numero intero:

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

Nota come gestisce quattro casi:  * digit è una lettera maiuscola A..F ,  * digit è una lettera minuscola a..f ,  * digit è una cifra decimale 0..9 e  * digit non è uno dei precedenti.

Ora usa la nuova funzione nella tua funzione originale:

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

Notate quanto appare più pulita la nuova funzione?

Se sei avventuroso, puoi usare questa funzione magica (che non gestisce input sbagliati, quindi devi verificarlo in anticipo):

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

Sostituisci tutto f [z] con una variabile dedicata. Assegna quella variabile con toupper (f [z])

Ecco un po 'di codice dal pacchetto Bloom NPS NSRL:

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

Questo codice è progettato per essere super veloce, gestire esagoni sia maiuscoli che minuscoli e gestire stringhe esagonali di qualsiasi lunghezza. La funzione nsrl_hex2bin () accetta un buffer binario, la dimensione di quel buffer e la stringa esadecimale che desideri convertire. Restituisce il numero di bit che sono stati effettivamente convertiti.

Oh, se vuoi solo un numero intero, allora puoi moltiplicare i byte (per il codice indipendente dall'endiano), o semplicemente fare un cast (per il codice dipendente dall'endiano).

Puoi provare sscanf invece:

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

Due opzioni:

Converti in maiuscolo prima di eseguire la scansione.

Aggiungi un secondo se nel ciclo quattro che gestisce le lettere minuscole.

Prova invece:

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

Tratta ancora l'input nello stesso modo del tuo (tendo a usare i puntatori ma a volte sono difficili da capire per un principiante) ma introduce tre casi separati, 0-9, AF e af, trattandoli in modo appropriato.

Il tuo codice originale consentirebbe effettivamente caratteri errati (i sei tra '9' e 'A') e produrrebbe risultati errati basati su di essi.

Nota che questo nuovo codice normalmente termina il ciclo solo alla fine della stringa. Trovare un carattere esadecimale non valido uscirà dal ciclo, funzionalmente identico alla tua condizione finale.

Usa strtol () per favore. Questa è la funzione C90 standard e molto più potente della maggior parte delle implementazioni ingenue. Supporta anche la conversione senza interruzioni da dec (nessun prefisso), hex (0x) e oct (a partire da 0).

E implementazione usando la rotazione dei turni invece della moltiplicazione.

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