Метод для преобразования из Hex в Integer в C, не может получить строчные буквы!

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

  •  06-07-2019
  •  | 
  •  

Вопрос

Привет всем, просто быстро, у меня работает шестнадцатеричное целое число, но мне нужно получить цифры в нижнем регистре. Вот что у меня есть, есть какие-нибудь идеи, чтобы получить регистр букв A & 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');
}

Возможно, это просто мелочь, но я бы хотел включить a-f и A-F. Спасибо за вашу помощь!

Это было полезно?

Решение

Если вы делаете это, чтобы узнать, как это сделать, игнорируйте этот пост. Если вы используете эту функцию, потому что вам нужно преобразовать строку шестнадцатеричных чисел в int , вы должны прогуляться по вашей стандартной библиотеке. Стандартная функция strtol () преобразует строку в long , который может быть приведен к int (или unsigned int , пока он у него был). Третий аргумент - это база, которую нужно преобразовать - в этом случае вам нужно, чтобы база 16 была шестнадцатеричной. Кроме того, если задано основание 0, оно будет принимать значение hex, если строка начинается с 0x , восьмеричное, если оно начинается с 0 , и десятичное в противном случае. Это очень полезная функция.

<Ч>

РЕДАКТИРОВАТЬ: только что заметил, но пока мы здесь, стоит упомянуть, что вы не должны обычно использовать int для индексации массивов. Стандарт C определяет тип, называемый size_t , который предназначен для хранения индексов массива. Обычно это unsigned int или unsigned long или что-то в этом роде, но гарантированно достаточно большой, чтобы хранить любой массив или смещение указателя, которое вы можете использовать.

Проблема с использованием только int заключается в том, что теоретически, может быть, когда-нибудь кто-нибудь сможет передать строку длиннее, чем INT_MAX , а затем ваш int переполнится, вероятно, обернется и начнет читать память, что, вероятно, не должно, потому что он использует отрицательный индекс. Это маловероятно, особенно для такой функции, потому что возвращаемое вами значение int будет переполнено задолго до переполнения счетчика int , но равно важно помнить.

Чтобы быть технически верным, вы должны использовать только переменные типа size_t для индексирования массивов или, по крайней мере, использовать только unsigned типы, если вы действительно не хотите пытаться получить доступ к отрицательным элементы (что обычно плохая идея, если вы не знаете, что делаете). Тем не менее, это не большая проблема здесь.

Другие советы

Создайте другую функцию, которая превращает шестнадцатеричное число в целое число:

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

Обратите внимание, как он обрабатывает четыре случая:  * цифра - это заглавная буква A..F ,  * цифра - это строчная буква a..f ,  * цифра является десятичной цифрой 0..9 и  * цифра не относится ни к одному из перечисленных выше.

Теперь используйте новую функцию в вашей исходной функции:

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

Обратите внимание, насколько чище выглядит новая функция?

Если вы любите приключения, вы можете использовать эту магическую функцию (которая не обрабатывает неверный ввод, поэтому вам нужно проверить это заранее):

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

Замените все f [z] выделенной переменной. Присвойте эту переменную с помощью toupper (f [z])

Вот код из пакета 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;
}

Этот код разработан для быстрой работы, обработки как шестнадцатеричных прописных, так и строчных букв, а также обработки шестнадцатеричных строк любой длины. Функция nsrl_hex2bin () принимает двоичный буфер, размер этого буфера и шестнадцатеричную строку, которую вы хотите преобразовать. Возвращает количество битов, которые фактически были преобразованы.

О, если вы хотите просто целое число, то вы можете умножить байты (для кода, независимого от порядка байтов), или просто выполнить приведение (для кода, зависящего от порядка байтов).

Вы можете вместо этого попробовать sscanf :

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

Два варианта:

Преобразуйте в верхний регистр перед сканированием.

Добавьте секунду, если в цикле четыре, который обрабатывает строчные буквы.

Попробуйте вместо этого:

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

Он по-прежнему обрабатывает вводные данные так же, как и ваши (я бы, как правило, использовал указатели, но их иногда трудно понять новичку), но вводит три отдельных случая, 0-9, AF и af, каждый из которых обрабатывается соответствующим образом.

Ваш исходный код на самом деле допускает ошибочные символы (шесть между «9» и «A») и дает неверные результаты на их основе.

Обратите внимание, что этот новый код обычно завершает цикл только в конце строки. Поиск недопустимого шестнадцатеричного символа вырвется из цикла, функционально идентичный вашему завершающему условию.

Используйте strtol (), пожалуйста. Это стандартная функция C90 и гораздо более мощная, чем большинство наивных реализаций. Он также поддерживает плавное преобразование из dec (без префикса), hex (0x) и oct (начиная с 0).

И реализация с использованием сдвига вращения вместо умножения.

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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top