c performance hex strtol

Convierte una cadena hexadecimal a un entero de manera eficiente en C?



performance strtol (15)

Para cadenas Hex más grandes como en el ejemplo, necesitaba usar strtoul .

En C, ¿cuál es la forma más eficiente de convertir una cadena de dígitos hexadecimales en un unsigned int binario o un unsigned long ?

Por ejemplo, si tengo 0xFFFFFFFE , quiero un int con el valor de base10 4294967294 .


¿Por qué es una solución de código que funciona para ser rechazada? Claro, es feo ...

Tal vez porque, además de ser feo, no es educativo y no funciona. Además, sospecho que, como yo, la mayoría de la gente no tiene el poder de editar en este momento (y a juzgar por el rango necesario, nunca lo hará).

El uso de una matriz puede ser bueno para la eficiencia, pero eso no se menciona en este código. Tampoco toma en cuenta mayúsculas y minúsculas, por lo que no funciona para el ejemplo proporcionado en la pregunta. FFFFFFFE


@Eric

De hecho, esperaba ver a un asistente de C publicar algo realmente genial, algo así como lo que hice, pero menos detallado, mientras lo hacía de forma "manual".

Bueno, no soy un gurú C, pero esto es lo que se me ocurrió:

unsigned int parseHex(const char * str) { unsigned int val = 0; char c; while(c = *str++) { val <<= 4; if (c >= ''0'' && c <= ''9'') { val += c & 0x0F; continue; } c &= 0xDF; if (c >= ''A'' && c <= ''F'') { val += (c & 0x07) + 9; continue; } errno = EINVAL; return 0; } return val; }

Originalmente tenía más enmascaramiento de bits en lugar de comparaciones, pero dudo mucho que la máscara de bits sea más rápida que la comparación en el hardware moderno.


Hexadecimal a decimal No lo ejecute en compiladores en línea, porque no funcionará.

#include<stdio.h> void main() { unsigned int i; scanf("%x",&i); printf("%d",i); }


Prueba esto:

#include <stdio.h> int main() { char s[] = "fffffffe"; int x; sscanf(s, "%x", &x); printf("%u/n", x); }


Actualmente, esto solo funciona con minúsculas, pero es muy fácil hacerlo funcionar con ambas.

cout << "/nEnter a hexadecimal number: "; cin >> hexNumber; orighex = hexNumber; strlength = hexNumber.length(); for (i=0;i<strlength;i++) { hexa = hexNumber.substr(i,1); if ((hexa>="0") && (hexa<="9")) { //cout << "This is a numerical value./n"; } else { //cout << "This is a alpabetical value./n"; if (hexa=="a"){hexa="10";} else if (hexa=="b"){hexa="11";} else if (hexa=="c"){hexa="12";} else if (hexa=="d"){hexa="13";} else if (hexa=="e"){hexa="14";} else if (hexa=="f"){hexa="15";} else{cout << "INVALID ENTRY! ANSWER WONT BE CORRECT/n";} } //convert from string to integer hx = atoi(hexa.c_str()); finalhex = finalhex + (hx*pow(16.0,strlength-i-1)); } cout << "The hexadecimal number: " << orighex << " is " << finalhex << " in decimal./n";


Intenta esto para convertir de decimal a hexadecimal

#include<stdio.h> #include<conio.h> int main(void) { int count=0,digit,n,i=0; int hex[5]; clrscr(); printf("enter a number "); scanf("%d",&n); if(n<10) { printf("%d",n); } switch(n) { case 10: printf("A"); break; case 11: printf("B"); break; case 12: printf("B"); break; case 13: printf("C"); break; case 14: printf("D"); break; case 15: printf("E"); break; case 16: printf("F"); break; default:; } while(n>16) { digit=n%16; hex[i]=digit; i++; count++; n=n/16; } hex[i]=n; for(i=count;i>=0;i--) { switch(hex[i]) { case 10: printf("A"); break; case 11: printf("B"); break; case 12: printf("C"); break; case 13: printf("D"); break; case 14: printf("E"); break; case 15: printf("F"); break; default: printf("%d",hex[i]); } } getch(); return 0; }


Si no tienes el stdlib, entonces tienes que hacerlo manualmente.

unsigned long hex2int(char *a, unsigned int len) { int i; unsigned long val = 0; for(i=0;i<len;i++) if(a[i] <= 57) val += (a[i]-48)*(1<<(4*(len-1-i))); else val += (a[i]-55)*(1<<(4*(len-1-i))); return val; }

Nota: Este código supone AF en mayúsculas. No funciona si len está más allá de su entero más largo 32 o 64 bits, y no hay ningún error de captura para caracteres hexadecimales ilegales.


#include "math.h" #include "stdio.h" /////////////////////////////////////////////////////////////// // The bits arg represents the bit say:8,16,32... ///////////////////////////////////////////////////////////// volatile long Hex_To_Int(long Hex,char bits) { long Hex_2_Int; char byte; Hex_2_Int=0; for(byte=0;byte<bits;byte++) { if(Hex&(0x0001<<byte)) Hex_2_Int+=1*(pow(2,byte)); else Hex_2_Int+=0*(pow(2,byte)); } return Hex_2_Int; } /////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////// void main (void) { int Dec; char Hex=0xFA; Dec= Hex_To_Int(Hex,8); //convert an 8-bis hexadecimal value to a number in base 10 printf("the number is %d",Dec); }


Como sucede a menudo, su pregunta adolece de un serio error / ambigüedad terminológica. En el habla común, por lo general no importa, pero en el contexto de este problema específico es de importancia crítica.

Usted ve, no hay tal cosa como "valor hexadecimal" y "valor decimal" (o "número hexadecimal" y "número decimal"). "Hex" y "decimal" son propiedades de representaciones de valores. Mientras tanto, los valores (o números) por sí mismos no tienen representación, por lo que no pueden ser "hexadecimales" o "decimales". Por ejemplo, la 0xF y 15 en C son dos representaciones diferentes del mismo número .

Supongo que su pregunta, tal como se afirma, sugiere que necesita convertir la representación hexadecimal ASCII de un valor (es decir, una cadena) en una representación decimal ASCII de un valor (otra cadena). Una forma de hacerlo es usar una representación entera como una intermedia: primero, convierta la representación hexadecimal ASCII a un número entero de tamaño suficiente (usando funciones de strto... group, como strtol ), luego convierta el entero en el decimal ASCII representación (usando sprintf ).

Si eso no es lo que tiene que hacer, entonces tiene que aclarar su pregunta, ya que es imposible entenderlo por la forma en que se formuló su pregunta.



Para los microcontroladores AVR escribí la siguiente función, incluidos los comentarios relevantes para que sea fácil de entender:

/** * hex2int * take a hex string and convert it to a 32bit number (max 8 hex digits) */ uint32_t hex2int(char *hex) { uint32_t val = 0; while (*hex) { // get current character then increment char byte = *hex++; // transform hex character to the 4bit equivalent number, using the ascii table indexes if (byte >= ''0'' && byte <= ''9'') byte = byte - ''0''; else if (byte >= ''a'' && byte <=''f'') byte = byte - ''a'' + 10; else if (byte >= ''A'' && byte <=''F'') byte = byte - ''A'' + 10; // shift 4 to make space for new digit, and add the 4 bits of the new digit val = (val << 4) | (byte & 0xF); } return val; }

Ejemplo:

char *z ="82ABC1EF"; uint32_t x = hex2int(z); printf("Number is [%X]/n", x);

Se producirá:


Editar: ahora es compatible con compiladores MSVC, C ++ y no GNU (ver final).

La pregunta era "la manera más eficiente". El OP no especifica la plataforma, podría estar compilando para un chip ATMEL basado en RISC con 256 bytes de almacenamiento flash para su código.

Para el registro, y para aquellos (como yo), que aprecian la diferencia entre "la manera más fácil" y la "manera más eficiente", y que disfrutan aprendiendo ...

static const long hextable[] = { [0 ... 255] = -1, // bit aligned access into this table is considerably [''0''] = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // faster for most modern processors, [''A''] = 10, 11, 12, 13, 14, 15, // for the space conscious, reduce to [''a''] = 10, 11, 12, 13, 14, 15 // signed char. }; /** * @brief convert a hexidecimal string to a signed long * will not produce or process negative numbers except * to signal error. * * @param hex without decoration, case insensitive. * * @return -1 on error, or result (max (sizeof(long)*8)-1 bits) */ long hexdec(unsigned const char *hex) { long ret = 0; while (*hex && ret >= 0) { ret = (ret << 4) | hextable[*hex++]; } return ret; }

No requiere bibliotecas externas, y debe ser deslumbrantemente rápido. Maneja mayúsculas, minúsculas, caracteres inválidos, entrada hexadecimal de tamaño impar (por ejemplo: 0xfff), y el tamaño máximo está limitado solo por el compilador.

Para compiladores o compiladores que no sean GCC o C ++ que no aceptarán la elegante declaración de hextable.

Reemplace la primera declaración con esta versión (más larga, pero más conforme):

static const long hextable[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };


@Eric

¿Por qué es una solución de código que funciona para ser rechazada? Claro, es feo y puede que no sea la forma más rápida de hacerlo, pero es más instructivo que decir "strtol" o "sscanf". Si lo intentas, aprenderás algo sobre cómo suceden las cosas bajo el capó.

Realmente no creo que tu solución haya sido rechazada, pero mi suposición de por qué está sucediendo es porque es menos práctica. La idea de votar es que la "mejor" respuesta flote hasta la cima, y ​​aunque tu respuesta podría ser más instructiva sobre lo que ocurre debajo del capó (o de qué manera podría suceder), definitivamente no es la mejor forma de analizar los números hexadecimales en un sistema de producción.

Una vez más, no creo que haya nada malo con su respuesta desde un punto de vista educativo, y desde luego no lo votaría (y no lo hice). No se desanime y deje de publicar solo porque a algunas personas no les gustó ninguna de sus respuestas. Sucede.

Dudo que mi respuesta lo haga sentir mejor si le rechazan a usted, pero sé que no es especialmente divertido cuando pregunta por qué se rechaza algo y nadie responde .


En C puede convertir un número hexadecimal a decimal de muchas maneras. Una forma es convertir el número hexadecimal a un número entero. Personalmente, me pareció simple y pequeño.

Aquí hay un código de muestra para convertir un número hexadecimal en un número decimal con la ayuda de un casting.

#include <stdio.h> int main(){ unsigned char Hexadecimal = 0x6D; //example hex number int Decimal = 0; //decimal number initialized to 0 Decimal = (int) Hexadecimal; //conversion printf("The decimal number is %d/n", Decimal); //output return 0; }