你如何将字节数组转换为C中的hexstring?

我有:

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

我想将字节数组转换为一个string,以便我可以使用printf打印string:

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

并得到(冒号没有必要):

 "00:01:0A:0B" 

任何帮助将不胜感激。

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

为更通用的方式:

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

连接到一个string,有几种方法可以做到这一点…我可能会保持一个指针的string的末尾,并使用sprintf。 你还应该跟踪数组的大小,以确保它不会比分配的空间大:

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

为了completude,你也可以轻松地做到这一点,而无需调用任何沉重的库函数(没有snprintf,没有strcat,甚至没有memcpy)。 如果你正在编写一些libc不可用的微控制器或操作系统内核,那么这会很有用。

没有什么真的想你可以find类似的代码,如果你谷歌。 真的,这并不比调用snprintf复杂得多,而且要快得多。

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

这是另一个稍微短一点的版本。 它仅仅避免了中间索引variablesi和复制了严格的case code(但终止字符被写了两次)。

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

下面是另一个版本来回答评论说,我用了一个“技巧”来知道input缓冲区的大小。 其实这不是一个技巧,而是一个必要的input知识(你需要知道你正在转换的数据的大小)。 我通过将转换代码提取到一个单独的函数来使得这个更清晰。 我还为目标缓冲区添加了边界检查代码,如果我们知道我们在做什么,这是不是真的有必要。

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

这是一种方法更快的方法:

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

我只是想添加下面的内容,即使它稍微偏离主题(不是标准C),但是我发现自己经常寻找它,并且在第一个search命中之间磕磕绊绊。 Linux内核打印函数printk还具有格式说明符,用于通过单个格式说明符“直接”输出数组/内存内容:

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

…但是,这些格式说明符似乎并不存在标准的用户空间(s)printf

上面已经存在类似的答案,我添加了这个来解释下面的代码行是如何工作的:

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

这是安静的棘手,不容易理解,我把解释在下面的评论:

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

在C中没有原始的。我可能malloc(或者可能alloca)足够长的缓冲区和循环的input。 我也看到它用一个类似于C ++的ostringstream带有语义(但不是语法)的dynamicstring库来完成,这是一个似是而非的通用解决scheme,但是对于单个案例来说,这可能不值得额外的复杂性。

如果要将hex值存储在char *string中,则可以使用snprintf 。 您需要为所有打印的字符分配空间,包括前导零和冒号。

扩大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 

所以现在str_buf将包含hexstring。

ZincX的解决scheme适用于包含冒号分隔符:

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

这是执行转换的一种方式:

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

我将在这里为任何感兴趣的人添加C ++版本。

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

它将打印长度countbufferstd::ostreamstd::ostream out (你可以使它默认为std::cout )。 每一行将包含bytes_per_line字节,每个字节用大写的两位hex表示。 字节之间会有空格。 并在行或缓冲区结束时,将打印一个换行符。 如果bytes_per_line设置为0,则不会打印new_line。 为自己而努力。

对于简单的用法,我做了一个函数,编码inputstring(二进制数据):

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

用法:

 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; 

稍微修改了Yannith版本。 这只是我想把它作为回报价值

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

用于C ++ 11

 #include <iostream> #include <string> #include <stdio.h> #include <unistd.h> template<typename F> void repeater(uint n, F f) { while(n--) f(); } std::string toString(uchar *data, uint len) { static const char *mask = "%02x"; static const uchar byteMaskLen = 2; // two symbols for byte std::string str; str.resize(len * byteMaskLen); char *c = const_cast<char*>(str.c_str()); for (uint i = 0; i < len; ++i) { sprintf(c, mask, *data++); repeater(byteMaskLen, [&c]{ *c = toupper(*c++); }); } *c = 0; return str; } 

这个函数适用于用户/调用者需要将hexstring放入字符数组/缓冲区的情况。 用字符缓冲区中的hexstring,用户/调用者可以使用自己的macros/函数来显示或者将其logging到任何它想要的地方(例如对于文件)。 这个函数还允许调用者控制每行的(hex)字节数。

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

例如:代码

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

OUTPUT

 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 

根据Yannuth的答案,但简化。

这里, dest[]长度暗示为len两倍,其分配由调用者pipe理。

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

复杂的解决scheme!
马洛克和冲刺和演员哦,我的。 (OZ报价)
而且在任何地方都没有单一的rem 天哪

这样的事情呢?

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