J'ai:
uint8 buf[] = {0, 1, 10, 11};
Je veux convertir le tableau d'octets en une chaîne de sorte que je puisse imprimer la chaîne en utilisant printf:
printf("%s\n", str);
et obtenir (les deux points ne sont pas nécessaires):
"00:01:0A:0B"
Toute aide serait grandement appréciée.
buf[i]
doit être jetéunsigned char
, ou il débordera sibuf[i] > 127
, c'est-à-dire:buf_ptr += sprintf(buf_ptr, "%02X", (unsigned char)buf[i]);
Réponses:
printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]);
pour une manière plus générique:
int i; for (i = 0; i < x; i++) { if (i > 0) printf(":"); printf("%02X", buf[i]); } printf("\n");
pour concaténer à une chaîne, il y a plusieurs façons de le faire ... Je garderais probablement un pointeur vers la fin de la chaîne et utiliserais sprintf. vous devez également garder une trace de la taille du tableau pour vous assurer qu'il ne dépasse pas l'espace alloué:
int i; char* buf2 = stringbuf; char* endofbuf = stringbuf + sizeof(stringbuf); for (i = 0; i < x; i++) { /* i use 5 here since we are going to add at most 3 chars, need a space for the end '\n' and need a null terminator */ if (buf2 + 5 < endofbuf) { if (i > 0) { buf2 += sprintf(buf2, ":"); } buf2 += sprintf(buf2, "%02X", buf[i]); } } buf2 += sprintf(buf2, "\n");
la source
printf("%02X", (unsigned char)buf[i]);
devrait être utilisé car l'original provoquera un débordement pour les caractères non signésprintf("%02hhX", buf[i])
?Pour être complet, vous pouvez également le faire facilement sans appeler de fonction de bibliothèque lourde (pas de snprintf, pas de strcat, même pas memcpy). Cela peut être utile, par exemple si vous programmez un microcontrôleur ou un noyau de système d'exploitation où la libc n'est pas disponible.
Rien de vraiment fantastique, vous pouvez trouver un code similaire si vous recherchez sur Google. Ce n'est vraiment pas beaucoup plus compliqué que d'appeler snprintf et beaucoup plus rapide.
#include <stdio.h> int main(){ unsigned char buf[] = {0, 1, 10, 11}; /* target buffer should be large enough */ char str[12]; unsigned char * pin = buf; const char * hex = "0123456789ABCDEF"; char * pout = str; int i = 0; for(; i < sizeof(buf)-1; ++i){ *pout++ = hex[(*pin>>4)&0xF]; *pout++ = hex[(*pin++)&0xF]; *pout++ = ':'; } *pout++ = hex[(*pin>>4)&0xF]; *pout++ = hex[(*pin)&0xF]; *pout = 0; printf("%s\n", str); }
Voici une autre version légèrement plus courte. Il évite simplement la variable d'index intermédiaire i et la duplication du dernier code de cas (mais le caractère de fin est écrit deux fois).
#include <stdio.h> int main(){ unsigned char buf[] = {0, 1, 10, 11}; /* target buffer should be large enough */ char str[12]; unsigned char * pin = buf; const char * hex = "0123456789ABCDEF"; char * pout = str; for(; pin < buf+sizeof(buf); pout+=3, pin++){ pout[0] = hex[(*pin>>4) & 0xF]; pout[1] = hex[ *pin & 0xF]; pout[2] = ':'; } pout[-1] = 0; printf("%s\n", str); }
Voici encore une autre version pour répondre à un commentaire disant que j'ai utilisé une "astuce" pour connaître la taille du tampon d'entrée. En fait, ce n'est pas une astuce mais une connaissance d'entrée nécessaire (vous devez connaître la taille des données que vous convertissez). J'ai clarifié cela en extrayant le code de conversion dans une fonction distincte. J'ai également ajouté un code de vérification des limites pour le tampon cible, ce qui n'est pas vraiment nécessaire si nous savons ce que nous faisons.
#include <stdio.h> void tohex(unsigned char * in, size_t insz, char * out, size_t outsz) { unsigned char * pin = in; const char * hex = "0123456789ABCDEF"; char * pout = out; for(; pin < in+insz; pout +=3, pin++){ pout[0] = hex[(*pin>>4) & 0xF]; pout[1] = hex[ *pin & 0xF]; pout[2] = ':'; if (pout + 3 - out > outsz){ /* Better to truncate output string than overflow buffer */ /* it would be still better to either return a status */ /* or ensure the target buffer is large enough and it never happen */ break; } } pout[-1] = 0; } int main(){ enum {insz = 4, outsz = 3*insz}; unsigned char buf[] = {0, 1, 10, 11}; char str[outsz]; tohex(buf, insz, str, outsz); printf("%s\n", str); }
la source
in
et le tampon de sortieout
? Je pourrais également opter pour l'utilisation d'une chaîne et renvoyer une copie au lieu de fournir un tampon de sortie, dans les optimiseurs C ++ modernes sont assez bons pour ne pas s'en soucier beaucoup.Voici une méthode beaucoup plus rapide:
#include <stdlib.h> #include <stdio.h> unsigned char * bin_to_strhex(const unsigned char *bin, unsigned int binsz, unsigned char **result) { unsigned char hex_str[]= "0123456789abcdef"; unsigned int i; if (!(*result = (unsigned char *)malloc(binsz * 2 + 1))) return (NULL); (*result)[binsz * 2] = 0; if (!binsz) return (NULL); for (i = 0; i < binsz; i++) { (*result)[i * 2 + 0] = hex_str[(bin[i] >> 4) & 0x0F]; (*result)[i * 2 + 1] = hex_str[(bin[i] ) & 0x0F]; } return (*result); } int main() { //the calling unsigned char buf[] = {0,1,10,11}; unsigned char * result; printf("result : %s\n", bin_to_strhex((unsigned char *)buf, sizeof(buf), &result)); free(result); return 0 }
la source
ca9e3c972f1c5db40c0b4a66ab5bc1a20ca4457bdbe5e0f8925896d5ed37d726
et vous en sortirezÌaÌe3cÌ72f1c5dÌ40c0b4a66Ìb5bÌ1Ì20cÌ4457bÌbÌ5Ì0Ì8Ì258Ì6Ì5Ìd37Ì726
. Pour résoudre ce problème, le bit à l'intérieurhex_str
de la première ligne de la boucle for doit être remplacé(input[i] >> 4) & 0x0F
par la réponse de @ kriss. Ensuite, cela fonctionne très bien.Des réponses similaires existent déjà ci-dessus, j'ai ajouté celle-ci pour expliquer comment la ligne de code suivante fonctionne exactement:
ptr += sprintf(ptr, "%02X", buf[i])
C'est assez délicat et pas facile à comprendre, je mets l'explication dans les commentaires ci-dessous:
uint8 buf[] = {0, 1, 10, 11}; /* Allocate twice the number of bytes in the "buf" array because each byte would * be converted to two hex characters, also add an extra space for the terminating * null byte. * [size] is the size of the buf array */ char output[(size * 2) + 1]; /* pointer to the first item (0 index) of the output array */ char *ptr = &output[0]; int i; for (i = 0; i < size; i++) { /* "sprintf" converts each byte in the "buf" array into a 2 hex string * characters appended with a null byte, for example 10 => "0A\0". * * This string would then be added to the output array starting from the * position pointed at by "ptr". For example if "ptr" is pointing at the 0 * index then "0A\0" would be written as output[0] = '0', output[1] = 'A' and * output[2] = '\0'. * * "sprintf" returns the number of chars in its output excluding the null * byte, in our case this would be 2. So we move the "ptr" location two * steps ahead so that the next hex string would be written at the new * location, overriding the null byte from the previous hex string. * * We don't need to add a terminating null byte because it's been already * added for us from the last hex string. */ ptr += sprintf(ptr, "%02X", buf[i]); } printf("%s\n", output);
la source
Je voulais juste ajouter ce qui suit, même s'il est légèrement hors sujet (pas le C standard), mais je me retrouve à le chercher souvent et à tomber sur cette question parmi les premiers résultats de recherche. La fonction d'impression du noyau Linux,,
printk
a également des spécificateurs de format pour sortir le contenu du tableau / de la mémoire "directement" via un spécificateur de format singulier:https://www.kernel.org/doc/Documentation/printk-formats.txt
Raw buffer as a hex string: %*ph 00 01 02 ... 3f %*phC 00:01:02: ... :3f %*phD 00-01-02- ... -3f %*phN 000102 ... 3f For printing a small buffers (up to 64 bytes long) as a hex string with certain separator. For the larger buffers consider to use print_hex_dump().
... cependant, ces spécificateurs de format ne semblent pas exister pour l'espace utilisateur standard
(s)printf
.la source
Solution
La fonction
btox
convertit les données arbitraires*bb
en une chaîne non terminée*xp
den
chiffres hexadécimaux:void btox(char *xp, const char *bb, int n) { const char xx[]= "0123456789ABCDEF"; while (--n >= 0) xp[n] = xx[(bb[n>>1] >> ((1 - (n&1)) << 2)) & 0xF]; }
Exemple
#include <stdio.h> typedef unsigned char uint8; void main(void) { uint8 buf[] = {0, 1, 10, 11}; int n = sizeof buf << 1; char hexstr[n + 1]; btox(hexstr, buf, n); hexstr[n] = 0; /* Terminate! */ printf("%s\n", hexstr); }
Résultat:
00010A0B
.En direct: Tio.run .
la source
Voici une façon d'effectuer la conversion:
#include<stdio.h> #include<stdlib.h> #define l_word 15 #define u_word 240 char *hex_str[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; main(int argc,char *argv[]) { char *str = malloc(50); char *tmp; char *tmp2; int i=0; while( i < (argc-1)) { tmp = hex_str[*(argv[i]) & l_word]; tmp2 = hex_str[*(argv[i]) & u_word]; if(i == 0) { memcpy(str,tmp2,1); strcat(str,tmp);} else { strcat(str,tmp2); strcat(str,tmp);} i++; } printf("\n********* %s *************** \n", str); }
la source
Version Yannith légèrement modifiée. C'est juste que j'aime l'avoir comme valeur de retour
typedef struct { size_t len; uint8_t *bytes; } vdata; char* vdata_get_hex(const vdata data) { char hex_str[]= "0123456789abcdef"; char* out; out = (char *)malloc(data.len * 2 + 1); (out)[data.len * 2] = 0; if (!data.len) return NULL; for (size_t i = 0; i < data.len; i++) { (out)[i * 2 + 0] = hex_str[(data.bytes[i] >> 4) & 0x0F]; (out)[i * 2 + 1] = hex_str[(data.bytes[i] ) & 0x0F]; } return out; }
la source
Cette fonction convient lorsque l'utilisateur / appelant souhaite qu'une chaîne hexadécimale soit placée dans un tableau / tampon de caractères. Avec une chaîne hexadécimale dans un tampon de caractères, l'utilisateur / appelant peut utiliser sa propre macro / fonction pour l'afficher ou la consigner à n'importe quel endroit de son choix (par exemple dans un fichier). Cette fonction permet également à l'appelant de contrôler le nombre d'octets (hexadécimaux) à mettre dans chaque ligne.
/** * @fn * get_hex * * @brief * Converts a char into bunary string * * @param[in] * buf Value to be converted to hex string * @param[in] * buf_len Length of the buffer * @param[in] * hex_ Pointer to space to put Hex string into * @param[in] * hex_len Length of the hex string space * @param[in] * num_col Number of columns in display hex string * @param[out] * hex_ Contains the hex string * @return void */ static inline void get_hex(char *buf, int buf_len, char* hex_, int hex_len, int num_col) { int i; #define ONE_BYTE_HEX_STRING_SIZE 3 unsigned int byte_no = 0; if (buf_len <= 0) { if (hex_len > 0) { hex_[0] = '\0'; } return; } if(hex_len < ONE_BYTE_HEX_STRING_SIZE + 1) { return; } do { for (i = 0; ((i < num_col) && (buf_len > 0) && (hex_len > 0)); ++i ) { snprintf(hex_, hex_len, "%02X ", buf[byte_no++] & 0xff); hex_ += ONE_BYTE_HEX_STRING_SIZE; hex_len -=ONE_BYTE_HEX_STRING_SIZE; buf_len--; } if (buf_len > 1) { snprintf(hex_, hex_len, "\n"); hex_ += 1; } } while ((buf_len) > 0 && (hex_len > 0)); }
Exemple: Code
#define DATA_HEX_STR_LEN 5000 char data_hex_str[DATA_HEX_STR_LEN]; get_hex(pkt, pkt_len, data_hex_str, DATA_HEX_STR_LEN, 16); // ^^^^^^^^^^^^ ^^ // Input byte array Number of (hex) byte // to be converted to hex string columns in hex string printf("pkt:\n%s",data_hex_str)
PRODUCTION
pkt: BB 31 32 00 00 00 00 00 FF FF FF FF FF FF DE E5 A8 E2 8E C1 08 06 00 01 08 00 06 04 00 01 DE E5 A8 E2 8E C1 67 1E 5A 02 00 00 00 00 00 00 67 1E 5A 01
la source
Il n'y a pas de primitive pour cela dans C. Je vais probablement malloc (ou peut-être alloca) un tampon assez long et une boucle sur l'entrée. Je l'ai également vu faire avec une bibliothèque de chaînes dynamiques avec une sémantique (mais pas une syntaxe!) Similaire à C ++
ostringstream
, qui est une solution plausiblement plus générique mais qui ne vaut peut-être pas la complexité supplémentaire juste pour un seul cas.la source
Si vous souhaitez stocker les valeurs hexadécimales dans une
char *
chaîne, vous pouvez utilisersnprintf
. Vous devez allouer de l'espace pour tous les caractères imprimés, y compris les zéros et deux-points de tête.Développant la réponse de Mark:
char str_buf* = malloc(3*X + 1); // X is the number of bytes to be converted int i; for (i = 0; i < x; i++) { if (i > 0) snprintf(str_buf, 1, ":"); snprintf(str_buf, 2, "%02X", num_buf[i]); // need 2 characters for a single hex value } snprintf(str_buf, 2, "\n\0"); // dont forget the NULL byte
Alors maintenant
str_buf
contiendra la chaîne hexadécimale.la source
La solution de ZincX adaptée pour inclure les délimiteurs du côlon:
char buf[] = {0,1,10,11}; int i, size = sizeof(buf) / sizeof(char); char *buf_str = (char*) malloc(3 * size), *buf_ptr = buf_str; if (buf_str) { for (i = 0; i < size; i++) buf_ptr += sprintf(buf_ptr, i < size - 1 ? "%02X:" : "%02X\0", buf[i]); printf("%s\n", buf_str); free(buf_str); }
la source
J'ajouterai la version C ++ ici pour toute personne intéressée.
#include <iostream> #include <iomanip> inline void print_bytes(char const * buffer, std::size_t count, std::size_t bytes_per_line, std::ostream & out) { std::ios::fmtflags flags(out.flags()); // Save flags before manipulation. out << std::hex << std::setfill('0'); out.setf(std::ios::uppercase); for (std::size_t i = 0; i != count; ++i) { auto current_byte_number = static_cast<unsigned int>(static_cast<unsigned char>(buffer[i])); out << std::setw(2) << current_byte_number; bool is_end_of_line = (bytes_per_line != 0) && ((i + 1 == count) || ((i + 1) % bytes_per_line == 0)); out << (is_end_of_line ? '\n' : ' '); } out.flush(); out.flags(flags); // Restore original flags. }
Il affichera le fichier hexadécimal de la
buffer
longueurcount
àstd::ostream
out
(vous pouvez le définir par défautstd::cout
). Chaque ligne contiendra desbytes_per_line
octets, chaque octet est représenté en majuscules hexadécimales à deux chiffres. Il y aura un espace entre les octets. Et à la fin de la ligne ou à la fin du tampon, il imprimera une nouvelle ligne. Sibytes_per_line
est défini sur 0, il n'imprimera pas new_line. Essayez par vous-même.la source
Pour une utilisation simple, j'ai créé une fonction qui encode la chaîne d'entrée (données binaires):
/* Encodes string to hexadecimal string reprsentation Allocates a new memory for supplied lpszOut that needs to be deleted after use Fills the supplied lpszOut with hexadecimal representation of the input */ void StringToHex(unsigned char *szInput, size_t size_szInput, char **lpszOut) { unsigned char *pin = szInput; const char *hex = "0123456789ABCDEF"; size_t outSize = size_szInput * 2 + 2; *lpszOut = new char[outSize]; char *pout = *lpszOut; for (; pin < szInput + size_szInput; pout += 2, pin++) { pout[0] = hex[(*pin >> 4) & 0xF]; pout[1] = hex[*pin & 0xF]; } pout[0] = 0; }
Usage:
unsigned char input[] = "This is a very long string that I want to encode"; char *szHexEncoded = NULL; StringToHex(input, strlen((const char *)input), &szHexEncoded); printf(szHexEncoded); // The allocated memory needs to be deleted after usage delete[] szHexEncoded;
la source
Basé sur la réponse de Yannuth mais simplifié.
Ici, la longueur de
dest[]
est implicitement égale à deux fois delen
, et son allocation est gérée par l'appelant.void create_hex_string_implied(const unsigned char *src, size_t len, unsigned char *dest) { static const unsigned char table[] = "0123456789abcdef"; for (; len > 0; --len) { unsigned char c = *src++; *dest++ = table[c >> 4]; *dest++ = table[c & 0x0f]; } }
la source
Je sais que cette question a déjà une réponse mais je pense que ma solution pourrait aider quelqu'un.
Donc, dans mon cas, j'avais un tableau d'octets représentant la clé et j'avais besoin de convertir ce tableau d'octets en tableau de caractères de valeurs hexadécimales afin de l'imprimer sur une ligne. J'ai extrait mon code vers une fonction comme celle-ci:
char const * keyToStr(uint8_t const *key) { uint8_t offset = 0; static char keyStr[2 * KEY_SIZE + 1]; for (size_t i = 0; i < KEY_SIZE; i++) { offset += sprintf(keyStr + offset, "%02X", key[i]); } sprintf(keyStr + offset, "%c", '\0'); return keyStr; }
Maintenant, je peux utiliser ma fonction comme ceci:
Serial.print("Public key: "); Serial.println(keyToStr(m_publicKey));
Serial
object fait partie de la bibliothèque Arduino etm_publicKey
est membre de ma classe avec la déclaration suivanteuint8_t m_publicKey[32]
.la source
Vous pouvez résoudre avec snprintf et malloc.
char c_buff[50]; u8_number_val[] = { 0xbb, 0xcc, 0xdd, 0x0f, 0xef, 0x0f, 0x0e, 0x0d, 0x0c }; char *s_temp = malloc(u8_size * 2 + 1); for (uint8_t i = 0; i < u8_size; i++) { snprintf(s_temp + i * 2, 3, "%02x", u8_number_val[i]); } snprintf(c_buff, strlen(s_temp)+1, "%s", s_temp ); printf("%s\n",c_buff); free(s);
SORTIE: bbccdd0fef0f0e0d0c
la source
Quelles solutions complexes!
Malloc et sprints et lancers oh mon Dieu. (Citation OZ)
et pas un seul rem nulle part. Gosh
Et quelque chose comme ça?
main() { // the value int value = 16; // create a string array with a '\0' ending ie. 0,0,0 char hex[]= {0,0,'\0'}; char *hex_p=hex; //a working variable int TEMP_int=0; // get me how many 16s are in this code TEMP_int=value/16; // load the first character up with // 48+0 gives you ascii 0, 55+10 gives you ascii A if (TEMP_int<10) {*hex_p=48+TEMP_int;} else {*hex_p=55+TEMP_int;} // move that pointer to the next (less significant byte)<BR> hex_p++; // get me the remainder after I have divied by 16 TEMP_int=value%16; // 48+0 gives you ascii 0, 55+10 gives you ascii A if (TEMP_int<10) {*hex_p=48+TEMP_int;} else {*hex_p=55+TEMP_int;} // print the result printf("%i , 0x%s",value,hex); }
la source