Método converter de Hex para Integer em C, não pode obter minúsculas!
Pergunta
Olá a todos, apenas uma coisa rápida, tenho o hexa para trabalho inteiro, mas eu preciso para obter os números de minúsculas. Aqui está o que eu tenho, todas as idéias para chegar a obter o A a F maiúsculas e 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');
}
Provavelmente apenas uma pequena coisa, mas eu gostaria de incluir a-f e A-F. Obrigado pela sua ajuda!
Solução
Se você está fazendo isso para aprender como fazê-lo, ignore este post. Se você estiver usando esta função, porque você precisa para converter uma seqüência de números hexadecimais para uma int
, você deve dar um passeio na sua biblioteca padrão. A função padrão strtol()
converte uma string para um long
, que pode ser derrubado para um int
(ou um unsigned int
enquanto estavam no). O terceiro argumento é a base para converter a - neste caso, você gostaria base 16 para hexadecimal. Além disso, se determinada base de 0, ele assumirá hex se a string começa com 0x
, octal se ele começa com 0
, e decimal contrário. É uma função muito útil.
EDIT: Só notei isso, mas enquanto estamos aqui, vale a pena mencionar que você geralmente não deve usar um int
para matrizes de índice. O padrão C define um tipo, chamado size_t
, que é concebido para armazenamento de índices de matriz. É geralmente uma unsigned int
ou unsigned long
ou algo assim, mas é garantido para ser grande o suficiente para armazenar qualquer matriz ou ponteiro deslocamento você pode usar.
O problema com o uso de apenas uma int
é que, teoricamente, talvez, algum dia, alguém poderia passar uma cadeia mais longa do que INT_MAX
, e então sua int
vai transbordar, provavelmente envolver em torno, e começar a ler memória que ele provavelmente não deveria porque é utilizando um índice negativo. Isto é altamente improvável, especialmente para uma função como esta, porque o valor int
você voltar vai transbordar muito antes de seu contador int
transborda, mas é uma coisa importante para se manter em mente.
Para ser tecnicamente correto, você só deve usar variáveis ??do tipo size_t
para matrizes de índice, ou pelo únicos tipos uso unsigned
menos importante, a menos que você realmente quer tentar elementos acesso negativos (que geralmente é uma má idéia se você não sabe o que você' está fazendo). No entanto, não é um grande problema aqui.
Outras dicas
Criar outra função que transforma um dígito hexadecimal para um número inteiro:
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 como ele lida com quatro casos:
* digit
é uma carta A..F
maiúsculas,
* digit
é uma carta a..f
minúscula,
* digit
é um dígito 0..9
decimal, e
* digit
é nenhuma das opções acima.
Agora, usar a nova função em sua função 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]);
}
}
Observe como muito mais limpo os novos olhares função?
Se você é aventureiro, você pode usar esta função mágica (que não manipular a entrada ruim, então você precisa verificar que de antemão):
int hex_digit_to_integer(char digit) {
return digit - (digit & 64 ? 55 : 48) & 15;
}
Substituir todos f [z] com uma variável dedicada. Atribuir essa variável com toupper (f [z])
Aqui está um código do pacote NPS CLRS 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 é projetado para ser super-rápido, lidar com ambos maiúsculas e minúsculas hex e cordas punho hexadecimais de qualquer comprimento. O nsrl_hex2bin function () leva um buffer binário, o tamanho desse buffer, ea cadeia hex você deseja converter. Ele retorna o número de bits que realmente se converteu.
Oh, se você quer apenas um inteiro, então você pode multiplicar os bytes (para código endian-independente), ou apenas fazer um elenco (para código endian-dependente).
Você poderia tentar sscanf vez:
#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;
}
Duas opções:
converter em maiúsculas antes de fazer a digitalização.
Adicionar um segundo, se nos quatro loop que alças minúsculas.
Tente isto em vez disso:
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;
}
É ainda trata a entrada da mesma forma que o seu (eu tendem a usar ponteiros, mas eles são, por vezes, difícil de entender por um novato), mas introduz três casos separados, 0-9, AF e AF, tratando cada adequadamente.
O seu código original seria realmente permitir caracteres incorretos (seis entre '9' e 'A') e produzir resultados incorretos com base nelas.
Note que este novo código só normalmente termina o loop no final da string. Encontrar um caractere hexadecimal inválido vai sair do loop, funcionalmente idêntica à sua condição de terminação.
Use strtol () por favor. Esta é a função C90 padrão e muito mais poderoso do que a maioria das implementações ingênuas. É também suportes sem costura conversão de dezembro (sem prefixo), hexagonal (0x) e outubro (começando com 0).
E implementação usando rotação turno em vez de multiplicação.
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;
}