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

Привет всем, просто быстро, у меня работает шестнадцатеричное целое число, но мне нужно получить цифры в нижнем регистре. Вот что у меня есть, есть какие-нибудь идеи, чтобы получить нечувствительный к регистру A?

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. Спасибо за вашу помощь!

Ответы [ 9 ]

7 голосов
/ 13 сентября 2009

Если вы делаете это, чтобы узнать, как это сделать, игнорируйте этот пост. Если вы используете эту функцию, потому что вам нужно преобразовать строку шестнадцатеричных чисел в 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 типы, если вы действительно не хотите пытаться получить доступ к отрицательным элементам (что обычно плохая идея, если вы знаю, что ты делаешь). Тем не менее, это не большая проблема здесь.

4 голосов
/ 13 сентября 2009

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

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

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

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

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;
}
2 голосов
/ 13 сентября 2009

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

1 голос
/ 13 сентября 2009

Вы можете попробовать 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;
}
1 голос
/ 13 сентября 2009

Вот код из пакета 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 () принимает двоичный буфер, размер этого буфера и шестнадцатеричную строку, которую вы хотите преобразовать. Возвращает количество битов, которые фактически были преобразованы.

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

0 голосов
/ 13 мая 2014

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

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;
}
0 голосов
/ 13 сентября 2009

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

0 голосов
/ 13 сентября 2009

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

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') и дает неверные результаты на их основе.

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

0 голосов
/ 13 сентября 2009

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

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

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

...