How to convert byte array to hexadecimal string in C?

I have:

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

I want to convert an array of bytes to a string in order to print the string using printf:

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

and get (colons are not needed):

 "00:01:0A:0B" 

Any help would be greatly appreciated.

+61
c string hex
Jun 15 '11 at 11:30
source share
15 answers
 printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]); 

for a more general way:

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

to concatenate a line, there are several ways to do this ... I would probably keep a pointer to the end of the line and use sprintf. you should also keep track of the size of the array to make sure that it will not be larger than the allocated space:

 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"); 
+64
Jun 15 '11 at 11:32
source share

To complete, you can also easily do this without calling any heavy library function (no snprintf, no strcat, even memcpy). This can be useful, say, if you are programming some kind of microcontroller or OS kernel where libc is not available.

Nothing special, you can find similar code if you conceived it. This is actually not much more complicated than calling snprintf and much faster.

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

Here is a slightly shorter version. It simply avoids the intermediate index variable i and duplicates the code of the last code (but the trailing character is written twice).

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

Below is another version for responding to a comment in which I used a "trick" to find out the size of the input buffer. Actually, this is not a trick, but the necessary input knowledge (you need to know the size of the data that you are converting). I made this clearer by extracting the conversion code into a separate function. I also added border control code for the target buffer, which is not needed if we know what we are doing.

 #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); } 
+20
Oct 11
source share

Here is a faster method:

 #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 } 
+13
Jun 17 '13 at 12:49 on
source share

I just wanted to add the following, even if it’s a little off topic (not standard C), but I find that I look for it often, and came across this question among the first search queries. The Linux kernel print function, printk , also has format specifiers for outputting the contents of the array / memory "directly" through a special format specifier:

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

... however, these format specifiers do not seem to exist for the standard user space (s)printf .

+5
Oct 30 '13 at
source share

Similar answers already exist above, I added this to explain how the following line of code works:

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

It is quiet and not easy to understand, I explained it in the comments below:

 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 null byte. * * We don't need to add a terminating null byte because it already added from * the last hex string. */ ptr += sprintf (ptr, "%02X", buf[i]); } printf ("%s\n", output); 
+3
Dec 15 '16 at 20:59
source share

This function is suitable when the user / caller wants the hexadecimal string to be placed in an array / character buffer. With a hexadecimal string in the character buffer, the user / caller can use his own macro / function to display or register anywhere he wants (for example, in a file). This feature also allows the caller to control the number of (hexadecimal) bytes for each line.

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

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

EXIT

 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 
+1
Dec 21 '16 at 13:53 on
source share

There is no primitive for this in C. I would suggest malloc (or perhaps alloca) a sufficiently long buffer and a loop over the input. I also saw how this is done with a dynamic library of strings with semantics (but not syntax!) ostringstream C ++ ostringstream , which is probably a more general solution, but maybe not worth the extra complexity for just one case.

0
Jun 15 2018-11-11T00:
source share

If you want to store the hexadecimal values ​​in a char * string, you can use snprintf . You need to allocate space for all printed characters, including leading zeros and a colon.

Deploy response to response:

 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 

So now str_buf will contain a hexadecimal string.

0
Jun 15 '11 at 12:05
source share

ZincX solution adapted to include colon dividers:

 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); } 
0
Dec 09 '11 at 12:04 on
source share

This is one way to do the 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); } 
0
Jul 26 '12 at 10:12
source share

I will add a C ++ version for anyone interested.

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

It will print a hexdump buffer length count up to std::ostream out (you can make it default std::cout ). Each line will contain bytes_per_line bytes, each byte is represented using uppercase two-digit hexadecimal numbers. There will be a space between bytes. And at the end of the line or the end of the buffer, a new line will be printed. If the bytes_per_line parameter bytes_per_line set to 0, it will not print new_line. Try it yourself.

0
Dec 01 '13 at 8:09
source share

For simple use, I created a function that encodes the input string (binary data):

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

Using:

 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; 
0
Nov 28 '15 at 11:36
source share

A slightly modified version of Yannith. I just like to have it as a return value

 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; } 
0
Jan 10 '16 at 1:27
source share

Based on Yannuth answer , but simplified.

Here the length of dest[] assumed to be twice the length of len , and its distribution is controlled by the caller.

 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]; } } 
0
Aug 16 '17 at 12:44 on
source share

What a difficult decision!
Malloc and sprint and throws about mine. (Quote OZ)
and nowhere else to go. Gosh

How about something like that?

 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); } 
-2
Oct 13 '14 at 10:20
source share



All Articles