Necesito convertir una cadena codificada hexadecimal como esta:
char hstr[9] = "61626364"; // characters abcd\0En
"abcd" // characters as hex: 0x61 0x62 0x63 0x64 // hex "digits" af are always lowercaseEn este momento escribí esta función:
#include <stdlib.h> void htostr(char* hexstr, char* str) { int len = strlen(hexstr); for (int i = 0; i < len/2; i++) // edit: fixed bounds { char input[3] = { hexstr[2 * i], hexstr[2 * i + 1], 0 }; *(str + i) = (char)strtol(input, NULL, 16); } } Estoy usando la función strtol para hacer el trabajo.
Siento que estoy desperdiciando 3 bytes de memoria para la matriz de input y algo de tiempo de procesador para copiar dos bytes y terminar con 0, porque la función strtol no tiene parámetros como "longitud".
Se supone que el código se ejecuta en un microcontrolador bastante ocupado, las cadenas son bastante largas (sería una buena idea liberar la memoria utilizada por hexstr lo antes posible).
La pregunta es: ¿existe una forma más eficiente de hacer esto sin escribir mi propio convertidor desde cero?
Por "desde cero" me refiero a conversión de bajo nivel sin usar la biblioteca estándar de funciones.
Cuando se le permite cambiar temporalmente la cadena de entrada:
void htostr_1(char* hexstr, char* str) { int len = strlen(hexstr); for (int i = 0; 2 * i + 2 <= len; i++) { char tmp = hexstr[2 * i + 2]; hexstr[2 * i + 2] = 0; str[i] = (char)strtol(hexstr + 2 * i, NULL, 16); hexstr[2 * i + 2] = tmp; } } Guarda el siguiente byte antes de terminar la cadena allí para deshacerlo después del strtol : https://godbolt.org/z/zdMdKrY7n
Como nota al margen: la condición final del ciclo for es incorrecta, accede fuera de los límites: https://godbolt.org/z/ra87cWocY
Si desea guardar también el int len y la innecesaria llamada strlen :
void htostr_2(char* hexstr, char* str) { while (*hexstr) { char tmp = hexstr[2]; hexstr[2] = 0; *str++ = (char)strtol(hexstr, NULL, 16); hexstr[2] = tmp; hexstr += 2; } }En lugar de copiar dos caracteres y usar strtol , podría crear una función que convierta los caracteres 0 .. 9 y A .. F en un int ( 0x0 a 0xF ).
#include <ctype.h> int toval(char ch) { if (isdigit((unsigned char)ch)) return ch - '0'; return toupper((unsigned char)ch) - 'A' + 0x10; }Luego, recorrer la cadena y sumar el resultado será bastante sencillo:
void htostr(char *wr, const char *rd) { for (; rd[0] != '\0' && rd[1] != '\0'; rd += 2, ++wr) { // multiply the first with 0x10 and add the value of the second *wr = toval(rd[0]) * 0x10 + toval(rd[1]); } *wr = '\0'; // null terminate }Ejemplo de uso:
#include <stdio.h> int main() { char hstr[] = "61626364"; char res[1 + sizeof hstr / 2]; htostr(res, hstr); printf(">%s<\n", res); }Si realmente quieres recortarlo:
void htostr(char* hexstr, char* str) { int i = 0; while (hexstr[2*i]) { { str[i] = 0; for (int j=0; j<2; j++) { str[i] <<= 4; char c = hexstr[2*i+j]; if (c >= '0' && c <= '9') { str[i] |= c - '0'; } else if (c >= 'A' && c <= 'F') { str[i] |= c - 'A' + 10; } else if (c >= 'a' && c <= 'f') { str[i] |= c - 'a' + 10; } } i++; } }