C语言 在 C 中如何将字节数组转换为十六进制字符串?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6357031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you convert a byte array to a hexadecimal string in C?
提问by Steve Walsh
I have:
我有:
uint8 buf[] = {0, 1, 10, 11};
I want to convert the byte array to a string such that I can print the string using printf:
我想将字节数组转换为字符串,以便可以使用 printf 打印字符串:
printf("%s\n", str);
and get (the colons aren't necessary):
并得到(不需要冒号):
"00:01:0A:0B"
Any help would be greatly appreciated.
任何帮助将不胜感激。
回答by Mark Synowiec
printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]);
for a more generic way:
更通用的方法:
int i;
for (i = 0; i < x; i++)
{
if (i > 0) printf(":");
printf("%02X", buf[i]);
}
printf("\n");
to concatenate to a string, there are a few ways you can do this... i'd probably keep a pointer to the end of the string and use sprintf. you should also keep track of the size of the array to make sure it doesnt get larger than the space allocated:
连接到一个字符串,有几种方法可以做到这一点......我可能会保留一个指向字符串末尾的指针并使用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");
回答by kriss
For completude, you can also easily do it without calling any heavy library function (no snprintf, no strcat, not even memcpy). It can be useful, say if you are programming some microcontroller or OS kernel where libc is not available.
为了完整起见,您还可以轻松完成,而无需调用任何繁重的库函数(没有 snprintf、没有 strcat,甚至没有 memcpy)。它可能很有用,例如,如果您正在编写一些 libc 不可用的微控制器或操作系统内核。
Nothing really fancy you can find similar code around if you google for it. Really it's not much more complicated than calling snprintf and much faster.
如果你用谷歌搜索,你可以找到类似的代码,没什么特别的。实际上,它并不比调用 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);
}
Here is another slightly shorter version. It merely avoid intermediate index variable i and duplicating laste case code (but the terminating character is written two times).
这是另一个略短的版本。它只是避免中间索引变量 i 和复制 laste case 代码(但终止字符被写入两次)。
#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 yet another version to answer to a comment saying I used a "trick" to know the size of the input buffer. Actually it's not a trick but a 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 to a separate function. I also added boundary check code for target buffer, which is not really necessary 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);
}
回答by Yannuth
Here is a method that is way way faster :
这是一种速度更快的方法:
#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
}
回答by razz
Similar answers already exist above, I added this one to explain how the following line of code works exactly:
上面已经存在类似的答案,我添加了这个来解释以下代码行的工作原理:
ptr += sprintf(ptr, "%02X", buf[i])
It's quiet tricky and not easy to understand, I put the explanation in the comments below:
它安静棘手且不易理解,我将解释放在下面的评论中:
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 => "0ARaw 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().
".
*
* 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 "0Avoid 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];
}
" would be written as output[0] = '0', output[1] = 'A' and
* output[2] = '#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);
}
'.
*
* "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);
回答by sdaau
I just wanted to add the following, even if it is slightly off-topic (not standard C), but I find myself looking for it often, and stumbling upon this question among the first search hits. The Linux kernel print function, printk, also has format specifiers for outputting array/memory contents "directly" through a singular format specifier:
我只是想添加以下内容,即使它有点偏离主题(不是标准 C),但我发现自己经常寻找它,并且在第一次搜索命中中偶然发现了这个问题。Linux 内核打印函数 ,printk也具有格式说明符,用于通过单一格式说明符“直接”输出数组/内存内容:
https://www.kernel.org/doc/Documentation/printk-formats.txt
https://www.kernel.org/doc/Documentation/printk-formats.txt
/**
* @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] = '#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)
';
}
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));
}
... however, these format specifiers do not seem to exist for the standard, user-space (s)printf.
...然而,这些格式说明符似乎不存在于标准的 user-space 中(s)printf。
回答by 7vujy0f0hy
Solution
解决方案
Function btoxconverts arbitrary data *bbto an unterminated string *xpof nhexadecimal digits:
函数btox将任意数据*bb转换为未终止*xp的n十六进制数字字符串:
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
Example
例子
#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);
}
Result: 00010A0B.
结果:00010A0B。
Live: Tio.run.
直播:Tio.run。
回答by Sandesh Kumar Sodhi
This function is suitable where user/caller wants hex string to be put in a charactee array/buffer. With hex string in a character buffer, user/caller can use its own macro/function to display or log it to any place it wants (e.g. to a file). This function also allows caller to control number of (hex) bytes to put in each line.
此函数适用于用户/调用者希望将十六进制字符串放入字符数组/缓冲区的情况。使用字符缓冲区中的十六进制字符串,用户/调用者可以使用自己的宏/函数将其显示或记录到它想要的任何位置(例如到文件)。此函数还允许调用者控制要放入每行的(十六进制)字节数。
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;
}
Example: Code
示例:代码
/* 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;
}
OUTPUT
输出
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;
回答by rajaganesh
This is one way of performing the conversion:
这是执行转换的一种方式:
##代码##回答by Mikhail Baynov
Slightly modified Yannith version. It is just I like to have it as a return value
稍微修改的 Yannith 版本。只是我喜欢把它作为返回值
回答by mbuster
For simple usage I made a function that encodes the input string (binary data):
为了简单使用,我制作了一个对输入字符串(二进制数据)进行编码的函数:
##代码##Usage:
用法:
##代码##
