58 votes

Chaîne hexadécimale en tableau d'octets en C

Existe-t-il une fonction C standard qui peut convertir une chaîne hexadécimale en tableau d'octets? Je ne veux pas écrire ma propre fonction s'il existe une méthode standard déjà existante.

71voto

Michael Foukarakis Points 14892

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 <stdio.h>

int main(int argc, char **argv)
{
    const char hexstring[] = "deadbeef10203040b00b1e50", *pos = hexstring;
    unsigned char val[12];
    size_t count = 0;

     /* WARNING: no sanitization or error-checking whatsoever */
    for(count = 0; count < sizeof(val)/sizeof(val[0]); count++) {
        sscanf(pos, "%2hhx", &val[count]);
        pos += 2 * sizeof(char);
    }

    printf("0x");
    for(count = 0; count < sizeof(val)/sizeof(val[0]); count++)
        printf("%02x", val[count]);
    printf("\n");

    return(0);
}
 

J'espère que cela t'aides.

Éditer

Comme l'a souligné Al, dans le cas d'un nombre impair de chiffres hexadécimaux dans la chaîne, vous devez vous assurer de le préfixer avec un 0 de départ. Par exemple, la chaîne "f00f5" sera évaluée comme {0xf0, 0x0f, 0x05} par erreur par l'exemple ci-dessus, au lieu du {0x0f, 0x00, 0xf5} approprié.

16voto

David M. Syzdek Points 4297

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 flux d'octets, mais va gérer 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);
}
 

8voto

dmckee Points 50318

Pour les chaînes courtes, strtol , strtoll et strtoimax fonctionneront très bien (notez que le troisième argument est la base à utiliser dans le traitement de la chaîne ... réglez-le sur 16). Si votre saisie est supérieure à 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.

2voto

cela ne fonctionne pas pour moi. Dans mon cas, sscanf écrit 4 octets à chaque itération. Je lance ce code sur Windows 7 32 bits de Visual C++ 2005. - Je convertir un hexa chaîne de 8 caractères("01020000"). Donc, mon val de tampon a une longueur de 4 octets.

Quand je regarde le vidage de mémoire, j'ai eu ce avant d'exécuter le code:

cd cd cd cd fd fd fd fd ab ab ab ab ab ab ab ab

Lors de la première itération, le 4 octets sont modifiées en même temps:

01 00 00 00 fd fd fd fd ab ab ab ab ab ab ab ab

Lors de la deuxième itération:

01 02 00 00 00 fd fd fd ab ab ab ab ab ab ab ab

Il y a ici un hors-lié à écrire. - Je résoudre ce problème avec un intermédiaire à court variable, et un seul " h " dans le sscanf format.

short tmpShort;
for(count = 0; count < sizeof(val)/sizeof(val[0]); count++) {
    sscanf(pos, "%2hx", &tmpShort);
    val[count] = tmpShort;
    pos += 2 * sizeof(char);
}

Parviendrez-vous à faire face au même problème?

0voto

Oli Charlesworth Points 148744

Non. Mais il est relativement trivial de réaliser l'utilisation de sscanf dans une boucle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X