¿Cómo convertir una cadena hexagonal en una matriz de caracteres sin signo?

Por ejemplo, tengo una cstring "E8 48 D8 FF FF 8B 0D" (espacios incluidos) que debe convertirse en la matriz de caracteres sin signo equivalente {0xE8,0x48,0xD8,0xFF,0xFF,0x8B,0x0D} . ¿Cuál es una manera eficiente de hacer esto? ¡Gracias!

EDITAR: No puedo usar la biblioteca estándar … así que considere esta una pregunta en C. ¡Lo siento!

Nunca me convencerás de que esta operación es un cuello de botella de rendimiento. La manera eficiente es hacer un buen uso de su tiempo mediante el uso de la biblioteca C estándar:

 static unsigned char gethex(const char *s, char **endptr) { assert(s); while (isspace(*s)) s++; assert(*s); return strtoul(s, endptr, 16); } unsigned char *convert(const char *s, int *length) { unsigned char *answer = malloc((strlen(s) + 1) / 3); unsigned char *p; for (p = answer; *s; p++) *p = gethex(s, (char **)&s); *length = p - answer; return answer; } 

Comstackdo y probado Funciona en tu ejemplo.

Esto responde a la pregunta original , que solicitó una solución de C ++.

Puedes usar un istringstream con el manipulador hex :

 std::string hex_chars("E8 48 D8 FF FF 8B 0D"); std::istringstream hex_chars_stream(hex_chars); std::vector bytes; unsigned int c; while (hex_chars_stream >> std::hex >> c) { bytes.push_back(c); } 

Tenga en cuenta que c debe ser un int (o long , o algún otro tipo entero), no un char ; si es un char (o unsigned char ), se invocará la >> sobrecarga incorrecta y se extraerán caracteres individuales de la cadena, no cadenas hexadecimales enteras.

La verificación de errores adicionales para garantizar que el valor extraído se ajusta dentro de un char sería una buena idea.

  • Itera a través de todos los personajes.
    • Si tiene un dígito hexadecimal, ¿el número es (ch >= 'A')? (ch - 'A' + 10): (ch - '0') (ch >= 'A')? (ch - 'A' + 10): (ch - '0') .
      • Mueva a la izquierda su acumulador en cuatro bits y agregue (o O) en el nuevo dígito.
    • Si tiene un espacio, y el carácter anterior no era un espacio, agregue su valor de acumulador actual a la matriz y restaure el acumulador a cero.

Si conoce la longitud de la cadena a analizar previamente (por ejemplo, está leyendo algo de / proc) puede usar sscanf con el modificador de tipo ‘hh’, que especifica que la siguiente conversión es una de diouxX y el puntero para almacenarla será firmado char o unsigned char.

 // example: ipv6 address as seen in /proc/net/if_inet6: char myString[] = "fe80000000000000020c29fffe01bafb"; unsigned char addressBytes[16]; sscanf(myString, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", &addressBytes[0], &addressBytes[1], &addressBytes[2], &addressBytes[3], &addressBytes[4], &addressBytes[5], &addressBytes[6], &addressBytes[7], &addressBytes[8], &addressBytes[9], &addressBytes[10], addressBytes[11],&addressBytes[12], &addressBytes[13], &addressBytes[14], &addressBytes[15]); int i; for (i = 0; i < 16; i++){ printf("addressBytes[%d] = %02x\n", i, addressBytes[i]); } 

Salida:

 addressBytes[0] = fe addressBytes[1] = 80 addressBytes[2] = 00 addressBytes[3] = 00 addressBytes[4] = 00 addressBytes[5] = 00 addressBytes[6] = 00 addressBytes[7] = 00 addressBytes[8] = 02 addressBytes[9] = 0c addressBytes[10] = 29 addressBytes[11] = ff addressBytes[12] = fe addressBytes[13] = 01 addressBytes[14] = ba addressBytes[15] = fb 

use la función “old” sscanf ():

 string s_hex = "E8 48 D8 FF FF 8B 0D"; // source string char *a_Char = new char( s_hex.length()/3 +1 ); // output char array for( unsigned i = 0, uchr ; i < s_hex.length() ; i += 3 ) { sscanf( s_hex.c_str()+ i, "%2x", &uchr ); // conversion a_Char[i/3] = uchr; // save as char } delete a_Char; 

Para una implementación de C pura, creo que puede persuadir a sscanf(3) para que haga qué. Creo que esto debería ser portátil (incluida la coerción de tipo poco fiable para apaciguar al comstackdor) siempre que su cadena de entrada solo contenga valores hexadecimales de dos caracteres.

 #include  #include  char hex[] = "E8 48 D8 FF FF 8B 0D"; char *p; int cnt = (strlen(hex) + 1) / 3; // Whether or not there's a trailing space unsigned char *result = (unsigned char *)malloc(cnt), *r; unsigned char c; for (p = hex, r = result; *p; p += 3) { if (sscanf(p, "%02X", (unsigned int *)&c) != 1) { break; // Didn't parse as expected } *r++ = c; } 

La vieja forma C, hazlo a mano 😉 (hay muchas formas más cortas, pero no estoy jugando al golf, voy a correr).

 enum { NBBYTES = 7 }; char res[NBBYTES+1]; const char * c = "E8 48 D8 FF FF 8B 0D"; const char * p = c; int i = 0; for (i = 0; i < NBBYTES; i++){ switch (*p){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': res[i] = *p - '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': res[i] = *p - 'A' + 10; break; default: // parse error, throw exception ; } p++; switch (*p){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': res[i] = res[i]*16 + *p - '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': res[i] = res[i]*16 + *p - 'A' + 10; break; default: // parse error, throw exception ; } p++; if (*p == 0) { continue; } if (*p == ' ') { p++; continue; } // parse error, throw exception } // let's show the result, C style IO, just cout if you want C++ for (i = 0 ; i < 7; i++){ printf("%2.2x ", 0xFF & res[i]); } printf("\n"); 

Ahora, otro que permite cualquier número de dígitos entre números, cualquier cantidad de espacios para separarlos, incluidos los espacios iniciales o finales (especificaciones de Ben):

 #include  #include  int main(){ enum { NBBYTES = 7 }; char res[NBBYTES]; const char * c = "E8 48 D8 FF FF 8B 0D"; const char * p = c; int i = -1; res[i] = 0; char ch = ' '; while (ch && i < NBBYTES){ switch (ch){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ch -= '0' + 10 - 'A'; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': ch -= 'A' - 10; res[i] = res[i]*16 + ch; break; case ' ': if (*p != ' ') { if (i == NBBYTES-1){ printf("parse error, throw exception\n"); exit(-1); } res[++i] = 0; } break; case 0: break; default: printf("parse error, throw exception\n"); exit(-1); } ch = *(p++); } if (i != NBBYTES-1){ printf("parse error, throw exception\n"); exit(-1); } for (i = 0 ; i < 7; i++){ printf("%2.2x ", 0xFF & res[i]); } printf("\n"); } 

No, no está realmente ofuscado ... pero bueno, parece que sí.