Chaîne hexadécimale à octet de tableau dans C

Existe-t-il une fonction C standard qui convertit une chaîne hexadécimale en un tableau d’octets ?
Je ne veux pas écrire ma propre fonction.

Pour autant que je sache, il n’y a pas de fonction standard pour le faire, mais c’est simple à réaliser de la manière suivante:

#include  int main(int argc, char **argv) { const char hexssortingng[] = "DEadbeef10203040b00b1e50", *pos = hexssortingng; unsigned char val[12]; /* WARNING: no sanitization or error-checking whatsoever */ for (size_t count = 0; count < sizeof val/sizeof *val; count++) { sscanf(pos, "%2hhx", &val[count]); pos += 2; } printf("0x"); for(size_t count = 0; count < sizeof val/sizeof *val; count++) printf("%02x", val[count]); printf("\n"); return 0; } 

modifier

Comme Al l'a fait remarquer, dans le cas d'un nombre impair de chiffres hexadécimaux dans la chaîne, vous devez vous assurer de lui atsortingbuer un préfixe 0. Par exemple, la chaîne "f00f5" sera évaluée comme {0xf0, 0x0f, 0x05} à tort par l'exemple ci-dessus, au lieu du {0x0f, 0x00, 0xf5} .

Modification de l'exemple un peu pour aborder le commentaire de @MassimoCallegari

J’ai trouvé cette question par Google pour la même chose. Je n’aime pas l’idée d’appeler sscanf () ou strtol () car cela semble exagéré. J’ai écrit une fonction rapide qui ne valide pas que le texte est bien la présentation hexadécimale d’un stream d’octets, mais gérera un nombre impair de chiffres hexadécimaux:

 uint8_t tallymarker_hextobin(const char * str, uint8_t * bytes, size_t blen) { uint8_t pos; uint8_t idx0; uint8_t idx1; // mapping of ASCII characters to hex values const uint8_t hashmap[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !"#$%&' 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ()*+,-./ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;< =>? 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // PQRSTUVW 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // XYZ[\]^_ 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // `abcdefg 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hijklmno 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pqrstuvw 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xyz{|}~. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ........ }; bzero(bytes, blen); for (pos = 0; ((pos < (blen*2)) && (pos < strlen(str))); pos += 2) { idx0 = (uint8_t)str[pos+0]; idx1 = (uint8_t)str[pos+1]; bytes[pos/2] = (uint8_t)(hashmap[idx0] << 4) | hashmap[idx1]; }; return(0); } 

Pour les chaînes courtes, strtol , strtoll et strtoimax fonctionnent strtoimax (notez que le troisième argument est la base à utiliser pour traiter la chaîne … réglez-la à 16). Si votre entrée est plus longue que le number-of-bits-in-the-longest-integer-type/4 vous aurez besoin d’une des méthodes les plus flexibles suggérées par d’autres réponses.

Mis à part les excellentes réponses ci-dessus, je pensais écrire une fonction C qui n’utilise aucune bibliothèque et qui dispose de quelques gardes contre les mauvaises chaînes.

 uint8_t* datahex(char* ssortingng) { if(ssortingng == NULL) return NULL; size_t slength = strlen(ssortingng); if((slength % 2) != 0) // must be even return NULL; size_t dlength = slength / 2; uint8_t* data = malloc(dlength); memset(data, 0, dlength); size_t index = 0; while (index < slength) { char c = string[index]; int value = 0; if(c >= '0' && c < = '9') value = (c - '0'); else if (c >= 'A' && c < = 'F') value = (10 + (c - 'A')); else if (c >= 'a' && c < = 'f') value = (10 + (c - 'a')); else { free(data); return NULL; } data[(index/2)] += value << (((index + 1) % 2) * 4); index++; } return data; } 

Explication:

une. index / 2 | La division entre entiers va arrondir la valeur, donc 0/2 = 0, 1/2 = 0, 2/2 = 1, 3/2 = 0 etc. Donc, pour 2 caractères de chaîne, nous ajoutons la valeur à 1 octet de données .

b. (indice + 1)% 2 | Nous voulons que les nombres impairs résultent à 1 et même à 0 puisque le premier chiffre d'une chaîne hexadécimale est le plus significatif et doit être multiplié par 16. Ainsi, pour l'index 0 => 0 + 1% 2 = 1, index 1 => 1 + 1% 2 = 0 etc.

c. < < 4 | Le décalage de 4 est multiplié par 16. Exemple: b00000001 < < 4 = b00010000

Par quelque modification du code de user411313, les travaux suivants pour moi:

 #include  #include  #include  int main () { char *hexssortingng = "deadbeef10203040b00b1e50"; int i; unsigned int bytearray[12]; uint8_t str_len = strlen(hexssortingng); for (i = 0; i < (str_len / 2); i++) { sscanf(hexstring + 2*i, "%02x", &bytearray[i]); printf("bytearray %d: %02x\n", i, bytearray[i]); } return 0; } 

Une version complète du post de Michael Foukarakis (puisque je n’ai pas encore la “réputation” pour append un commentaire à cet article):

 #include  #include  void print(unsigned char *byte_array, int byte_array_size) { int i = 0; printf("0x"); for(; i < byte_array_size; i++) { printf("%02x", byte_array[i]); } printf("\n"); } int convert(const char *hex_str, unsigned char *byte_array, int byte_array_max) { int hex_str_len = strlen(hex_str); int i = 0, j = 0; // The output array size is half the hex_str length (rounded up) int byte_array_size = (hex_str_len+1)/2; if (byte_array_size > byte_array_max) { // Too big for the output array return -1; } if (hex_str_len % 2 == 1) { // hex_str is an odd length, so assume an implicit "0" prefix if (sscanf(&(hex_str[0]), "%1hhx", &(byte_array[0])) != 1) { return -1; } i = j = 1; } for (; i < hex_str_len; i+=2, j++) { if (sscanf(&(hex_str[i]), "%2hhx", &(byte_array[j])) != 1) { return -1; } } return byte_array_size; } void main() { char *examples[] = { "", "5", "D", "5D", "5Df", "deadbeef10203040b00b1e50", "02invalid55" }; unsigned char byte_array[128]; int i = 0; for (; i < sizeof(examples)/sizeof(char *); i++) { int size = convert(examples[i], byte_array, 128); if (size < 0) { printf("Failed to convert '%s'\n", examples[i]); } else if (size == 0) { printf("Nothing to convert for '%s'\n", examples[i]); } else { print(byte_array, size); } } } 

Non, mais il est relativement sortingvial d’utiliser sscanf en boucle.

 char *hexssortingng = "deadbeef10203040b00b1e50", *pos = hexssortingng; unsigned char val[12]; while( *pos ) { if( !((pos-hexssortingng)&1) ) sscanf(pos,"%02x",&val[(pos-hexssortingng)>>1]); ++pos; } 

sizeof (val) / sizeof (val [0]) est redondant!

  In main() { printf("enter ssortingng :\n"); fgets(buf, 200, stdin); unsigned char str_len = strlen(buf); k=0; unsigned char bytearray[100]; for(j=0;j64) temp=10+(temp-65); else temp=temp-48; fin=(temp< <4)&0xf0; temp = toupper(*(val+1)); if(temp>64) temp=10+(temp-65); else temp=temp-48; fin=fin|(temp & 0x0f); return fin; } 

Ceci est une fonction modifiée d’une question similaire, modifiée selon la suggestion de https://stackoverflow.com/a/18267932/700597 .

Cette fonction convertira une chaîne hexadécimale – NON précédée de “0x” – avec un nombre pair de caractères jusqu’au nombre d’octets spécifié. Il renverra -1 s’il rencontre un caractère non valide ou si la chaîne hexadécimale a une longueur impaire et 0 si elle réussit.

 //convert hexssortingng to len bytes of data //returns 0 on success, -1 on error //data is a buffer of at least len bytes //hexssortingng is upper or lower case hexadecimal, NOT prepended with "0x" int hex2data(unsigned char *data, const unsigned char *hexssortingng, unsigned int len) { unsigned const char *pos = hexssortingng; char *endptr; size_t count = 0; if ((hexssortingng[0] == '\0') || (strlen(hexssortingng) % 2)) { //hexssortingng contains no data //or hexssortingng has an odd length return -1; } for(count = 0; count < len; count++) { char buf[5] = {'0', 'x', pos[0], pos[1], 0}; data[count] = strtol(buf, &endptr, 0); pos += 2 * sizeof(char); if (endptr[0] != '\0') { //non-hexadecimal character encountered return -1; } } return 0; } 

Voici HexToBin et BinToHex relativement propres et lisibles. (Notez à l’origine que des codes d’erreur d’énumération ont été renvoyés via un système de journalisation des erreurs non simple -1 ou -2.)

 typedef unsigned char ByteData; ByteData HexChar (char c) { if ('0' < = c && c <= '9') return (ByteData)(c - '0'); if ('A' <= c && c <= 'F') return (ByteData)(c - 'A' + 10); if ('a' <= c && c <= 'f') return (ByteData)(c - 'a' + 10); return (ByteData)(-1); } ssize_t HexToBin (const char* s, ByteData * buff, ssize_t length) { ssize_t result = 0; if (!s || !buff || length <= 0) return -2; while (*s) { ByteData nib1 = HexChar(*s++); if ((signed)nib1 < 0) return -3; ByteData nib2 = HexChar(*s++); if ((signed)nib2 < 0) return -4; ByteData bin = (nib1 << 4) + nib2; if (length-- <= 0) return -5; *buff++ = bin; ++result; } return result; } void BinToHex (const ByteData * buff, ssize_t length, char * output, ssize_t outLength) { char binHex[] = "0123456789ABCDEF"; if (!output || outLength < 4) return (void)(-6); *output = '\0'; if (!buff || length <= 0 || outLength <= 2 * length) { memcpy(output, "ERR", 4); return (void)(-7); } for (; length > 0; --length, outLength -= 2) { ByteData byte = *buff++; *output++ = binHex[(byte >> 4) & 0x0F]; *output++ = binHex[byte & 0x0F]; } if (outLength-- < = 0) return (void)(-8); *output++ = '\0'; } 

hextools.h

 #ifndef HEX_TOOLS_H #define HEX_TOOLS_H char *bin2hex(unsigned char*, int); unsigned char *hex2bin(const char*); #endif // HEX_TOOLS_H 

hextools.c

 #include  char *bin2hex(unsigned char *p, int len) { char *hex = malloc(((2*len) + 1)); char *r = hex; while(len && p) { (*r) = ((*p) & 0xF0) >> 4; (*r) = ((*r) < = 9 ? '0' + (*r) : 'A' - 10 + (*r)); r++; (*r) = ((*p) & 0x0F); (*r) = ((*r) <= 9 ? '0' + (*r) : 'A' - 10 + (*r)); r++; p++; len--; } *r = '\0'; return hex; } unsigned char *hex2bin(const char *str) { int len, h; unsigned char *result, *err, *p, c; err = malloc(1); *err = 0; if (!str) return err; if (!*str) return err; len = 0; p = (unsigned char*) str; while (*p++) len++; result = malloc((len/2)+1); h = !(len%2) * 4; p = result; *p = 0; c = *str; while(c) { if(('0' <= c) && (c <= '9')) *p += (c - '0') << h; else if(('A' <= c) && (c <= 'F')) *p += (c - 'A' + 10) << h; else if(('a' <= c) && (c <= 'f')) *p += (c - 'a' + 10) << h; else return err; str++; c = *str; if (h) h = 0; else { h = 4; p++; *p = 0; } } return result; } 

principal c

 #include  #include "hextools.h" int main(void) { unsigned char s[] = { 0xa0, 0xf9, 0xc3, 0xde, 0x44 }; char *hex = bin2hex(s, sizeof s); puts(hex); unsigned char *bin; bin = hex2bin(hex); puts(bin2hex(bin, 5)); size_t k; for(k=0; k<5; k++) printf("%02X", bin[k]); putchar('\n'); return 0; } 

Essayez le code suivant:

 static unsigned char ascii2byte(char *val) { unsigned char temp = *val; if(temp > 0x60) temp -= 39; // convert chars af temp -= 48; // convert chars 0-9 temp *= 16; temp += *(val+1); if(*(val+1) > 0x60) temp -= 39; // convert chars af temp -= 48; // convert chars 0-9 return temp; } 

Voici ma version:

 /* Convert a hex char digit to its integer value. */ int hexDigitToInt(char digit) { digit = tolower(digit); if ('0' < = digit && digit <= '9') //if it's decimal return (int)(digit - '0'); else if ('a' <= digit && digit <= 'f') //if it's abcdef return (int)(digit - ('a' - 10)); else return -1; //value not in [0-9][af] range } /* Decode a hex string. */ char *decodeHexString(const char *hexStr) { char* decoded = malloc(strlen(hexStr)/2+1); char* hexStrPtr = (char *)hexStr; char* decodedPtr = decoded; while (*hexStrPtr != '\0') { /* Step through hexStr, two chars at a time. */ *decodedPtr = 16 * hexDigitToInt(*hexStrPtr) + hexDigitToInt(*(hexStrPtr+1)); hexStrPtr += 2; decodedPtr++; } *decodedPtr = '\0'; /* final null char */ return decoded; } 

Pourrait-il être plus simple?!

 uint8_t hex(char ch) { uint8_t r = (ch > 57) ? (ch - 55) : (ch - 48); return r & 0x0F; } int to_byte_array(const char *in, size_t in_size, uint8_t *out) { int count = 0; if (in_size % 2) { while (*in && out) { *out = hex(*in++); if (!*in) return count; *out = (*out < < 4) | hex(*in++); *out++; count++; } return count; } else { while (*in && out) { *out++ = (hex(*in++) << 4) | hex(*in++); count++; } return count; } } int main() { char hex_in[] = "deadbeef10203040b00b1e50"; uint8_t out[32]; int res = to_byte_array(hex_in, sizeof(hex_in) - 1, out); for (size_t i = 0; i < res; i++) printf("%02x ", out[i]); printf("\n"); system("pause"); return 0; }