Wie konvertiert man ein Byte-Array in eine hexadezimale Zeichenfolge in C?

Ich habe:

uint8 buf[] = {0, 1, 10, 11}; 

Ich möchte das Byte-Array in eine Zeichenfolge konvertieren, so dass ich die Zeichenfolge mit printf drucken kann:

 printf("%s\n", str); 

und bekommen (die Doppelpunkte sind nicht notwendig):

 "00:01:0A:0B" 

Jede Hilfe würde sehr geschätzt werden.

 printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]); 

für eine allgemeinere Art:

 int i; for (i = 0; i < x; i++) { if (i > 0) printf(":"); printf("%02X", buf[i]); } printf("\n"); 

Um mit einer Zeichenkette zu verketten, gibt es ein paar Möglichkeiten, wie Sie das tun können … Ich würde wahrscheinlich einen pointers auf das Ende der Zeichenkette halten und sprintf verwenden. Sie sollten auch die Größe des Arrays verfolgen, um sicherzustellen, dass es nicht größer als der zugewiesene Speicherplatz wird:

 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"); 

Ganz einfach können Sie es auch ohne eine schwere Bibliotheksfunktion aufrufen (kein snprintf, kein strcat, nicht einmal memcpy). Es kann nützlich sein, sagen Sie, wenn Sie einen Mikrocontroller oder OS-coreel programmieren, wo libc nicht verfügbar ist.

Nichts wirklich Besonderes, dass Sie ähnlichen Code herum finden können, wenn Sie dafür googeln. Wirklich ist es nicht viel komplizierter als snprintf und viel schneller anzurufen.

 #include  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); } 

Hier ist eine weitere etwas kürzere Version. Es vermeidet lediglich die Zwischenindexvariable i und den Duplikationscode für den letzten Fall (das abschließende Zeichen wird jedoch zweimal geschrieben).

 #include  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); } 

Unten ist noch eine andere Version, um auf einen Kommentar zu antworten, dass ich einen “Trick” verwendet habe, um die Größe des Eingabepuffers zu kennen. Eigentlich ist es kein Trick, sondern ein notwendiges Input-Wissen (Sie müssen die Größe der Daten kennen, die Sie konvertieren). Ich machte dies klarer, indem ich den Konvertierungscode in eine separate function extrahierte. Ich habe auch einen Grenzkontrollcode für den Zielpuffer hinzugefügt, was nicht wirklich notwendig ist, wenn wir wissen, was wir tun.

 #include  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); } 

Hier ist eine Methode, die viel schneller ist:

 #include  #include  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 } 

Ähnliche Antworten existieren bereits oben, ich habe dieses hinzugefügt, um zu erklären, wie die folgende Codezeile genau funktioniert:

 ptr += sprintf (ptr, "%02X", buf[i]) 

Es ist leise, knifflig und nicht leicht zu verstehen. Ich lege die Erklärung in die Kommentare unten:

 uint8 buf[] = {0, 1, 10, 11}; /* Allocate twice the number of the 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 to 2 chars hex string and a null byte, for example * 10 => "0A\0". * * These three chars would be added to the output array starting from * the ptr location, for example if ptr is pointing at 0 index then the hex chars * "0A\0" would be written as output[0] = '0', output[1] = 'A' and output[2] = '\0'. * * sprintf returns the number of chars written execluding the null byte, in our case * this would be 2. Then we move the ptr location two steps ahead so that the next * hex char would be written just after this one and overriding this one's null byte. * * We don't need to add a terminating null byte because it's already added from * the last hex string. */ ptr += sprintf (ptr, "%02X", buf[i]); } printf ("%s\n", output); 

Ich wollte nur das Folgende hinzufügen, auch wenn es etwas außerhalb des Themas ist (nicht Standard C), aber ich finde mich oft darauf, und stolpere über diese Frage unter den ersten Suchtreffern. Die print-function des Linux-coreels, printk , verfügt auch über Formatbezeichner für die Ausgabe von printk / Speicherinhalten “direkt” über einen einzelnen Formatbezeichner:

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(). 

… diese Formatbezeichner scheinen jedoch nicht für den Standard-Benutzerbereich (s)printf .

Diese function ist geeignet, wenn der Benutzer / Aufrufer Hexadezimalzeichenfolge in ein Zeichenfeld / -puffer eingeben möchte. Mit hexadezimalen Zeichenfolgen in einem Zeichenpuffer kann der Benutzer / Aufrufer sein eigenes Makro / seine eigene function verwenden, um es an einer beliebigen Stelle anzuzeigen oder zu protokollieren (z. B. in einer Datei). Diese function ermöglicht es dem Aufrufer auch, die Anzahl der (Hex-) Bytes zu steuern, die in jede Zeile eingefügt werden.

 /** * @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)); } 

Beispiel: 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) 

AUSGABE

 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 

Dafür gibt es kein primitives Element in C. Ich würde wahrscheinlich einen Puffer verwenden, der lange genug ist (oder vielleicht alloziert), um die Eingabe zu durchlaufen. Ich habe es auch mit einer dynamischen String-Bibliothek mit Semantik (aber nicht mit Syntax!) ostringstream , die ähnlich wie C ++ ostringstream , was eine plausibelere generische Lösung ist, aber es ist vielleicht nicht die zusätzliche Komplexität für einen einzelnen Fall wert.

Wenn Sie die snprintf in einer char * Zeichenfolge speichern möchten, können Sie snprintf . Sie müssen für alle gedruckten Zeichen, einschließlich der führenden Nullen und des Doppelpunkts, Platz reservieren.

Erweitern Sie Marks Antwort:

 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 

Also wird str_buf jetzt die str_buf Zeichenfolge enthalten.

Die Lösung von ZincX ist so angepasst, dass sie Doppelpunktbegrenzer enthält:

 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); } 

Dies ist eine Möglichkeit, die Konvertierung durchzuführen:

 #include #include #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); } 

Ich werde die C ++ – Version hier für jeden, der daran interessiert ist, hinzufügen.

 #include  #include  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(static_cast(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. } 

Es wird den hexdump des buffer der Länge count zu std::ostream out (Sie können es standardmäßig auf std::cout ). Jede Zeile enthält bytes_per_line Bytes, jedes Byte wird mit zweistelligen Hexadezimalzahlen dargestellt. Zwischen den Bytes wird ein Leerzeichen stehen. Und am Ende der Zeile oder am Ende des Puffers wird ein Zeilenumbruch gedruckt. Wenn bytes_per_line auf 0 gesetzt ist, wird new_line nicht gedruckt. Probieren Sie es selbst aus.

Zur einfachen Verwendung habe ich eine function erstellt, die die Eingabezeichenfolge (Binärdaten) codiert:

 /* 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; } 

Verwendung:

 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; 

Leicht modifizierte Yannith-Version. Es ist nur ich mag es als Rückgabewert haben

 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; } 

Basierend auf Yannuths Antwort, aber vereinfacht.

Hier wird die Länge von dest[] impliziert, dass sie zweimal von len , und ihre Zuweisung wird vom Aufrufer verwaltet.

 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]; } } 

Welche komplexen Lösungen!
Malloc und Sprints und wirft oh mein. (OZ Zitat)
und nicht eine einzige rem irgendwo. Meine Güte

Wie wäre es mit so etwas?

 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)
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); }