如何在C中将字节数组转换为十六进制字符串?

| 我有:
uint8 buf[] = {0, 1, 10, 11};
我想将字节数组转换为字符串,以便可以使用printf打印该字符串:
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\");
要连接到字符串,有几种方法可以执行此操作...我可能会保留一个指向字符串末尾的指针并使用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的微控制器或OS内核,这可能会很有用。 如果您用google搜索,没有什么真正的幻想。确实,它并没有比调用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);
}
这是另一个稍短的版本。它仅避免中间索引变量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);
}
下面是回答评论的另一个版本,该评论说我使用“技巧”来知道输入缓冲区的大小。实际上,这不是技巧,而是必要的输入知识(您需要知道要转换的数据的大小)。通过将转换代码提取到一个单独的函数中,我使这一点变得更加清晰。我还为目标缓冲区添加了边界检查代码,如果我们知道自己在做什么,则实际上并没有必要。
#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
}
    
        上面已经存在类似的答案,我添加了此答案以解释以下代码行的确切工作方式:
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语言),但我发现自己也经常在寻找它,并且在第一个搜索结果中遇到了这个问题。 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
,似乎不存在这些格式说明符。     
        解 函数
btox
将任意数据
*bb
转换为十六进制数字
n
的无终止字符串
*xp
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];
}
#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);
}
结果:
00010A0B
。 直播:Tio.run。     
        这是执行转换的一种方式:
#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);

}
    
        略微修改了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;
}
        此功能适用于用户/调用者希望将十六进制字符串放入字符数组/缓冲区的情况。在字符缓冲区中使用十六进制字符串时,用户/调用者可以使用自己的宏/函数将其显示或记录到所需的任何位置(例如,文件中)。此函数还允许调用方控制要放入每行中的(十六进制)字节数。
/**
 * @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) 
输出值
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 
    
        C语言中没有用于此的原语。我可能会malloc(或可能是alloca)足够长的缓冲区并在输入上循环。我还看到它是使用具有类似于C ++的
ostringstream
的语义(但不是语法!)的动态字符串库完成的,这似乎是更通用的解决方案,但仅在单个情况下可能并不值得额外的复杂性。     
        如果要将十六进制值存储在
char *
字符串中,则可以使用
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
将包含十六进制字符串。     
        ZincX的解决方案适用于包含冒号分隔符:
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);
}
    
        我将在这里为感兴趣的任何人添加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.
}
它将打印长度为
count
buffer
std::ostream
out
的十六进制转储(您可以将其默认设置为
std::cout
)。每行将包含39个字节,每个字节均使用大写两位数十六进制表示。字节之间将有一个空格。在行尾或缓冲区末尾,它将打印换行符。如果
bytes_per_line
设置为0,则不会打印new_line。自己尝试。     
为了简单使用,我制作了一个对输入字符串(二进制数据)进行编码的函数:
/* 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;
    
        基于Yannuth的答案,但已简化。 这里,,43ѭ的长度隐含为
len
的两倍,并且其分配由呼叫者管理。
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];
    }
}
    
        我知道这个问题已经有了答案,但是我认为我的解决方案可以帮助某人。 因此,在我的情况下,我有一个表示键的字节数组,我需要将此字节数组转换为十六进制值的char数组,以便将其打印在一行中。我将代码提取到如下所示的函数中:
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;
}
现在,我可以这样使用我的函数:
Serial.print(\"Public key: \");
Serial.println(keyToStr(m_publicKey));
Serial
对象是Arduino库的一部分,
m_publicKey
是我的类的成员,带有以下声明
uint8_t m_publicKey[32]
。     
        您可以使用snprintf和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);
出: bbccdd0fef0f0e0d0c     
        有什么复杂的解决方案! Malloc,冲刺并施展哦,我的天。 (OZ报价) 而不是任何地方。天哪 这样的事情怎么样?
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);

}
    

要回复问题请先登录注册