【问题标题】:Hexadecimal string to byte array in CC中的十六进制字符串到字节数组
【发布时间】:2011-03-25 10:26:48
【问题描述】:

是否有任何标准的 C 函数可以将十六进制字符串转换为字节数组
我不想编写自己的函数。

【问题讨论】:

  • 你的意思是一个字符串,其中包含代表十六进制数字的字符?
  • 是的,我有任何长度 >= 0 的用户输入字符串,例如“abCD12ff34”,我想将其转换为字节数组,例如 0xaa、0xcd、0x12 等

标签: c string


【解决方案1】:

据我所知,没有标准的功能可以做到这一点,但是通过以下方式实现很简单:

#include <stdio.h>

int main(int argc, char **argv) {
    const char hexstring[] = "DEadbeef10203040b00b1e50", *pos = hexstring;
    unsigned char val[12];

     /* WARNING: no sanitization or error-checking whatsoever */
    for (size_t count = 0; count < sizeof val/sizeof *val; count++) {
        sscanf(pos, "%2hhx", &val[count]);
        pos += 2;
    }

    printf("0x");
    for(size_t count = 0; count < sizeof val/sizeof *val; count++)
        printf("%02x", val[count]);
    printf("\n");

    return 0;
}

编辑

正如 Al 指出的,如果字符串中有奇数个十六进制数字,您必须确保在其前面加上一个起始 0。例如,字符串 "f00f5" 将被错误地评估为 {0xf0, 0x0f, 0x05}通过上面的例子,而不是正确的{0x0f, 0x00, 0xf5}

稍微修改了示例以解决来自@MassimoCallegari 的评论

【讨论】:

  • 这是一个很好的方法,但请注意,如果十六进制字符串中有奇数个数字,它将给出不正确的结果(隐式零将作为最后一个数字的前缀,而不是第一个,因此“5ab5c”将打印为 0x5ab50c 而不是 0x05ab5c)。
  • 字节序在这里不重要吗?
  • @Geremia 不。仅当您将字节数组重新解释为整数类型时,字节序才会发挥作用,反之亦然。 commandcenter.blogspot.com/2012/04/byte-order-fallacy.html ED:除非你很奇怪并以小端顺序编写十六进制文字。无论哪种方式,这都会获取每对数字并将它们转换为单个字节;生成的字节序与原始字节序相同。
  • 如果源字符串是大写的,这是否有效?例如。 “死牛……”
  • @MassimoCallegari,是的,因为 scanf 的 x 转换说明符适用于 strtoul 之类的字符串,它需要 C11 6.4.4.1 中定义的输入。
【解决方案2】:

我通过谷歌搜索发现了这个问题。我不喜欢调用 sscanf() 或 strtol() 的想法,因为这感觉有点矫枉过正。我写了一个快速函数,它不能验证文本确实是字节流的十六进制表示,但会处理奇数个十六进制数字:

uint8_t tallymarker_hextobin(const char * str, uint8_t * bytes, size_t blen)
{
   uint8_t  pos;
   uint8_t  idx0;
   uint8_t  idx1;

   // mapping of ASCII characters to hex values
   const uint8_t hashmap[] =
   {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //  !"#$%&'
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ()*+,-./
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
     0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
     0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // PQRSTUVW
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // XYZ[\]^_
     0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // `abcdefg
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hijklmno
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pqrstuvw
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xyz{|}~.
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // ........
   };

   bzero(bytes, blen);
   for (pos = 0; ((pos < (blen*2)) && (pos < strlen(str))); pos += 2)
   {
      idx0 = (uint8_t)str[pos+0];
      idx1 = (uint8_t)str[pos+1];
      bytes[pos/2] = (uint8_t)(hashmap[idx0] << 4) | hashmap[idx1];
   };

   return(0);
}

【讨论】:

  • 您可以通过添加 4 条逻辑指令将映射大小减少到 32 字节,这是一个很好的权衡:idx0 = (uint8_t)str[pos+0] &amp; 0x1F ^ 0x10;idx1 相同。那么您可以删除01234567 行之前的所有字节以及HIJKLMNO 行之后的所有字节
  • @5andr0,作为要点发布:gist.github.com/vi/dd3b5569af8a26b97c8e20ae06e804cb。虽然没有检查。
  • sscanfstrtol 是多余的,但不必要的 32 行十六进制表不是吗?
  • for (pos = 0; ((pos &lt; (blen*2)) &amp;&amp; (pos &lt; strlen(str))); pos += 2) 对于超过 255 的字符串,此行将失败,因为 pos 是 uint8_t,因此循环条件将始终评估为 true
  • @zibri 运行 1,000,000 次迭代,我的代码平均 0.011 秒完成,您的代码平均 0.113 秒。我对矫枉过正的评论是关于运行时效率的。回顾 cmets,关于如何改进我的代码(包括检查 pos 变量以进行循环)几乎没有什么好的建议。作为旁注,您应该在编写输出函数时始终包括边界检查,因为如果输入十六进制长于输出缓冲区,您的函数可能会导致缓冲区溢出。
【解决方案3】:

除了上面的优秀答案之外,虽然我会编写一个不使用任何库并且对坏字符串有一些防范措施的 C 函数。

uint8_t* datahex(char* string) {

    if(string == NULL) 
       return NULL;

    size_t slength = strlen(string);
    if((slength % 2) != 0) // must be even
       return NULL;

    size_t dlength = slength / 2;

    uint8_t* data = malloc(dlength);
    memset(data, 0, dlength);

    size_t index = 0;
    while (index < slength) {
        char c = string[index];
        int value = 0;
        if(c >= '0' && c <= '9')
          value = (c - '0');
        else if (c >= 'A' && c <= 'F') 
          value = (10 + (c - 'A'));
        else if (c >= 'a' && c <= 'f')
          value = (10 + (c - 'a'));
        else {
          free(data);
          return NULL;
        }

        data[(index/2)] += value << (((index + 1) % 2) * 4);

        index++;
    }

    return data;
}

解释:

一个。索引 / 2 |整数之间的除法将舍入该值,因此 0/2 = 0、1/2 = 0、2/2 = 1、3/2 = 1、4/2 = 2、5/2 = 2 等。所以,对于每 2 个字符串字符,我们将值添加到 1 个数据字节。

b. (指数 + 1) % 2 |我们希望奇数的结果为 1,偶数的结果为 0,因为十六进制字符串的第一个数字是最重要的,需要乘以 16。所以对于索引 0 => 0 + 1 % 2 = 1,索引 1 => 1 + 1 % 2 = 0 等等。

c. |移位 4 是乘以 16。例如:b00000001

【讨论】:

  • 即使失败了。 if(slength % 2 == 0) 应该是 if(slength % 2 != 0)。否则似乎工作。
  • 谢谢!刚刚修好了。
  • 不错的一个。非常适合嵌入式。
  • @MikeM 请注意在您的例程中返回指向动态分配缓冲区 (data) 的指针!那不是c风格,让用户喂缓冲
  • 似乎有内存泄漏。如果遇到非十六进制字符,则返回“NULL”,但不会释放分配的“数据”缓冲区。
【解决方案4】:

对于短字符串,strtolstrtollstrtoimax 可以正常工作(请注意,第三个参数是用于处理字符串的基数...将其设置为 16)。如果您的输入比number-of-bits-in-the-longest-integer-type/4 长,那么您将需要其他答案建议的更灵活的方法之一。

【讨论】:

    【解决方案5】:

    Michael Foukarakis 帖子的充实版本(因为我还没有为该帖子添加评论的“声誉”):

    #include <stdio.h>
    #include <string.h>
    
    void print(unsigned char *byte_array, int byte_array_size)
    {
        int i = 0;
        printf("0x");
        for(; i < byte_array_size; i++)
        {
            printf("%02x", byte_array[i]);
        }
        printf("\n");
    }
    
    int convert(const char *hex_str, unsigned char *byte_array, int byte_array_max)
    {
        int hex_str_len = strlen(hex_str);
        int i = 0, j = 0;
    
        // The output array size is half the hex_str length (rounded up)
        int byte_array_size = (hex_str_len+1)/2;
    
        if (byte_array_size > byte_array_max)
        {
            // Too big for the output array
            return -1;
        }
    
        if (hex_str_len % 2 == 1)
        {
            // hex_str is an odd length, so assume an implicit "0" prefix
            if (sscanf(&(hex_str[0]), "%1hhx", &(byte_array[0])) != 1)
            {
                return -1;
            }
    
            i = j = 1;
        }
    
        for (; i < hex_str_len; i+=2, j++)
        {
            if (sscanf(&(hex_str[i]), "%2hhx", &(byte_array[j])) != 1)
            {
                return -1;
            }
        }
    
        return byte_array_size;
    }
    
    void main()
    {
        char *examples[] = { "", "5", "D", "5D", "5Df", "deadbeef10203040b00b1e50", "02invalid55" };
        unsigned char byte_array[128];
        int i = 0;
    
        for (; i < sizeof(examples)/sizeof(char *); i++)
        {
            int size = convert(examples[i], byte_array, 128);
            if (size < 0)
            {
                printf("Failed to convert '%s'\n", examples[i]);
            }
            else if (size == 0)
            {
                printf("Nothing to convert for '%s'\n", examples[i]);
            }
            else
            {
                print(byte_array, size);
            }
        }
    }
    

    【讨论】:

      【解决方案6】:

      通过修改用户411313的代码,以下对我有用:

      #include <stdio.h>
      #include <stdint.h> 
      #include <string.h>
      
      int main ()
      {
          char *hexstring = "deadbeef10203040b00b1e50";
          int i;
          unsigned int bytearray[12];
          uint8_t str_len = strlen(hexstring);
      
          for (i = 0; i < (str_len / 2); i++) {
              sscanf(hexstring + 2*i, "%02x", &bytearray[i]);
              printf("bytearray %d: %02x\n", i, bytearray[i]);
          }
      
          return 0;
      }
      

      【讨论】:

      • 这也会写到缓冲区的末尾。
      • int i; ... uint8_t str_len 都应该是size_t
      • 这段代码还允许十六进制字节之间有空格,例如char *hexstring = "de ad be ef 10 20 30 40 b0 0b 1e 50";,它工作正常。伟大的!编辑:但我们应该调整循环。
      • 12 可以用str_len 代替,也许只是char数组来节省空间?
      【解决方案7】:

      这里是 HexToBin 和 BinToHex 比较干净和可读。 (注意最初是通过错误记录系统返回的枚举错误代码,而不是简单的 -1 或 -2。)

      typedef unsigned char ByteData;
      ByteData HexChar (char c)
      {
          if ('0' <= c && c <= '9') return (ByteData)(c - '0');
          if ('A' <= c && c <= 'F') return (ByteData)(c - 'A' + 10);
          if ('a' <= c && c <= 'f') return (ByteData)(c - 'a' + 10);
          return (ByteData)(-1);
      }
      
      ssize_t HexToBin (const char* s, ByteData * buff, ssize_t length)
      {
          ssize_t result = 0;
          if (!s || !buff || length <= 0) return -2;
      
          while (*s)
          {
              ByteData nib1 = HexChar(*s++);
              if ((signed)nib1 < 0) return -3;
              ByteData nib2 = HexChar(*s++);
              if ((signed)nib2 < 0) return -4;
      
              ByteData bin = (nib1 << 4) + nib2;
      
              if (length-- <= 0) return -5;
              *buff++ = bin;
              ++result;
          }
          return result;
      }
      
      void BinToHex (const ByteData * buff, ssize_t length, char * output, ssize_t outLength)
      {
          char binHex[] = "0123456789ABCDEF";
      
          if (!output || outLength < 4) return (void)(-6);
          *output = '\0';
      
          if (!buff || length <= 0 || outLength <= 2 * length)
          {
              memcpy(output, "ERR", 4);
              return (void)(-7);
          }
      
          for (; length > 0; --length, outLength -= 2)
          {
              ByteData byte = *buff++;
      
              *output++ = binHex[(byte >> 4) & 0x0F];
              *output++ = binHex[byte & 0x0F];
          }
          if (outLength-- <= 0) return (void)(-8);
          *output++ = '\0';
      }
      

      【讨论】:

        【解决方案8】:

        hextools.h

        #ifndef HEX_TOOLS_H
        #define HEX_TOOLS_H
        
        char *bin2hex(unsigned char*, int);
        
        unsigned char *hex2bin(const char*);
        
        #endif // HEX_TOOLS_H
        

        hextools.c

        #include <stdlib.h>
        
        char *bin2hex(unsigned char *p, int len)
        {
            char *hex = malloc(((2*len) + 1));
            char *r = hex;
        
            while(len && p)
            {
                (*r) = ((*p) & 0xF0) >> 4;
                (*r) = ((*r) <= 9 ? '0' + (*r) : 'A' - 10 + (*r));
                r++;
                (*r) = ((*p) & 0x0F);
                (*r) = ((*r) <= 9 ? '0' + (*r) : 'A' - 10 + (*r));
                r++;
                p++;
                len--;
            }
            *r = '\0';
        
            return hex;
        }
        
        unsigned char *hex2bin(const char *str)
        {
            int len, h;
            unsigned char *result, *err, *p, c;
        
            err = malloc(1);
            *err = 0;
        
            if (!str)
                return err;
        
            if (!*str)
                return err;
        
            len = 0;
            p = (unsigned char*) str;
            while (*p++)
                len++;
        
            result = malloc((len/2)+1);
            h = !(len%2) * 4;
            p = result;
            *p = 0;
        
            c = *str;
            while(c)
            {
                if(('0' <= c) && (c <= '9'))
                    *p += (c - '0') << h;
                else if(('A' <= c) && (c <= 'F'))
                    *p += (c - 'A' + 10) << h;
                else if(('a' <= c) && (c <= 'f'))
                    *p += (c - 'a' + 10) << h;
                else
                    return err;
        
                str++;
                c = *str;
        
                if (h)
                    h = 0;
                else
                {
                    h = 4;
                    p++;
                    *p = 0;
                }
            }
        
            return result;
        }
        

        main.c

        #include <stdio.h>
        #include "hextools.h"
        
        int main(void)
        {
            unsigned char s[] = { 0xa0, 0xf9, 0xc3, 0xde, 0x44 };
        
            char *hex = bin2hex(s, sizeof s);
            puts(hex);
        
            unsigned char *bin;
            bin = hex2bin(hex);
        
            puts(bin2hex(bin, 5));
        
            size_t k;
            for(k=0; k<5; k++)
                printf("%02X", bin[k]);
        
            putchar('\n');
        
            return 0;
        }
        

        【讨论】:

          【解决方案9】:

          以下是我出于性能原因编写的解决方案:

          void hex2bin(const char* in, size_t len, unsigned char* out) {
          
            static const unsigned char TBL[] = {
               0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  58,  59,  60,  61,
              62,  63,  64,  10,  11,  12,  13,  14,  15,  71,  72,  73,  74,  75,
              76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
              90,  91,  92,  93,  94,  95,  96,  10,  11,  12,  13,  14,  15
            };
          
            static const unsigned char *LOOKUP = TBL - 48;
          
            const char* end = in + len;
          
            while(in < end) *(out++) = LOOKUP[*(in++)] << 4 | LOOKUP[*(in++)];
          
          }
          

          例子:

          unsigned char seckey[32];
          
          hex2bin("351aaaec0070d13d350afae2bc43b68c7e590268889869dde489f2f7988f3fee", 64, seckey);
          
          /*
            seckey = {
               53,  26, 170, 236,   0, 112, 209,  61,  53,  10, 250, 226, 188,  67, 182, 140, 
              126,  89,   2, 104, 136, 152, 105, 221, 228, 137, 242, 247, 152, 143,  63, 238
            };
          */
          

          如果不需要支持小写:

          static const unsigned char TBL[] = {
               0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  58,  59,
              60,  61,  62,  63,  64,  10,  11,  12,  13,  14,  15
          };
          

          【讨论】:

          • 警告:对 'in' [-Wunsequenced] 进行多次未排序的修改
          • 您正在使用双“in++”调用未定义的行为。
          【解决方案10】:
          char *hexstring = "deadbeef10203040b00b1e50", *pos = hexstring;
          unsigned char val[12];
          while( *pos )
          {
            if( !((pos-hexstring)&1) )
              sscanf(pos,"%02x",&val[(pos-hexstring)>>1]);
            ++pos;
          }
          

          sizeof(val)/sizeof(val[0]) 是多余的!

          【讨论】:

          • 这会写到缓冲区的末尾!此外,只需 p+=2 而不是 &1 检查。
          • unsigned char val[12];...sscanf(pos,"%02x",&amp;val[...]); 是错误的,因为它试图将 unsigned 存储到 unsigned char 中。
          【解决方案11】:
              In main()
              {
          printf("enter string :\n");
              fgets(buf, 200, stdin);
          unsigned char str_len = strlen(buf);
          k=0;
          unsigned char bytearray[100];
               for(j=0;j<str_len-1;j=j+2)
                  { bytearray[k++]=converttohex(&buffer[j]);   
                          printf(" %02X",bytearray[k-1]);
                  }
          
              }
          
              Use this 
          
              int converttohex(char * val)
                  {
                  unsigned char temp = toupper(*val);
                  unsigned char fin=0;
                  if(temp>64)
                  temp=10+(temp-65);
          
                  else
                  temp=temp-48;
          
                  fin=(temp<<4)&0xf0;
          
                  temp = toupper(*(val+1));
          
                      if(temp>64)
                      temp=10+(temp-65);
          
                      else
                      temp=temp-48;
          
                  fin=fin|(temp & 0x0f);
          
          
                     return fin;
                  }
          

          【讨论】:

            【解决方案12】:

            这是一个类似问题的修改函数,根据https://stackoverflow.com/a/18267932/700597的建议修改。

            此函数会将偶数个字符的十六进制字符串(不以“0x”开头)转换为指定的字节数。如果遇到无效字符,或者十六进制字符串的长度为奇数,它将返回 -1,成功则返回 0。

            //convert hexstring to len bytes of data
            //returns 0 on success, -1 on error
            //data is a buffer of at least len bytes
            //hexstring is upper or lower case hexadecimal, NOT prepended with "0x"
            int hex2data(unsigned char *data, const unsigned char *hexstring, unsigned int len)
            {
                unsigned const char *pos = hexstring;
                char *endptr;
                size_t count = 0;
            
                if ((hexstring[0] == '\0') || (strlen(hexstring) % 2)) {
                    //hexstring contains no data
                    //or hexstring has an odd length
                    return -1;
                }
            
                for(count = 0; count < len; count++) {
                    char buf[5] = {'0', 'x', pos[0], pos[1], 0};
                    data[count] = strtol(buf, &endptr, 0);
                    pos += 2 * sizeof(char);
            
                    if (endptr[0] != '\0') {
                        //non-hexadecimal character encountered
                        return -1;
                    }
                }
            
                return 0;
            }
            

            【讨论】:

              【解决方案13】:

              使用 strchr() 解析字节或单词的两个简短例程。

              // HexConverter.h
              #ifndef HEXCONVERTER_H
              #define HEXCONVERTER_H
              unsigned int hexToByte (const char *hexString);
              unsigned int hexToWord (const char *hexString);
              #endif
              
              
              // HexConverter.c
              #include <string.h> // for strchr()
              #include <ctype.h>  // for toupper()
              
              unsigned int hexToByte (const char *hexString)
              {
                  unsigned int value;
                  const char *hexDigits = "0123456789ABCDEF";
              
                  value = 0;
                  if (hexString != NULL)
                  {
                      char *ptr;
              
                      ptr = strchr (hexDigits, toupper(hexString[0]));
                      if (ptr != NULL)
                      {
                          value = (ptr - hexDigits) << 4;
              
                          ptr = strchr (hexDigits, toupper(hexString[1]));
                          if (ptr != NULL)
                          {
                              value = value | (ptr - hexDigits);
                          }
                      }
                  }
              
                  return value;
              }
              
              unsigned int hexToWord (const char *hexString)
              {
                  unsigned int value;
              
                  value = 0;
                  if (hexString != NULL)
                  {
                      value = (hexToByte (&hexString[0]) << 8) |
                              (hexToByte (&hexString[2]));
                  }
              
                  return value;
              }
              
              
              // HexConverterTest.c
              #include <stdio.h>
              
              #include "HexConverter.h"
              
              int main (int argc, char **argv)
              {
                  (void)argc; // not used
                  (void)argv; // not used
              
                  unsigned int value;
                  char *hexString;
              
                  hexString = "2a";
                  value = hexToByte (hexString);
                  printf ("%s == %x (%u)\n", hexString, value, value);
              
                  hexString = "1234";
                  value = hexToWord (hexString);
                  printf ("%s == %x (%u)\n", hexString, value, value);
              
                  hexString = "0102030405060708090a10ff";
                  printf ("Hex String: %s\n", hexString);
                  for (unsigned int idx = 0; idx < strlen(hexString); idx += 2)
                  {
                      value = hexToByte (&hexString[idx]);
                      printf ("%c%c == %x (%u)\n", hexString[idx], hexString[idx+1],
                              value, value);
                  }
              
                  return EXIT_SUCCESS;
              }

              【讨论】:

                【解决方案14】:

                你可以使用这个功能

                1. 编写时考虑了性能(针对嵌入式处理器),没有scanfstrtoldynamic memory allocation
                2. 防止输出缓冲区溢出和奇数输入str len
                /// in: valid chars are 0-9 + A-F + a-f
                /// out_len_max==0: convert until the end of input string, out_len_max>0 only convert this many numbers
                /// returns actual out size
                int hexStr2Arr(unsigned char* out, const char* in, size_t out_len_max = 0)
                {
                    if (!out_len_max)
                        out_len_max = 2147483647; // INT_MAX
                
                    const int in_len = strnlen(in, out_len_max * 2);
                    if (in_len % 2 != 0)
                        return -1; // error, in str len should be even
                
                    // calc actual out len
                    const int out_len = out_len_max < (in_len / 2) ? out_len_max : (in_len / 2);
                
                    for (int i = 0; i < out_len; i++) {
                        char ch0 = in[2 * i];
                        char ch1 = in[2 * i + 1];
                        uint8_t nib0 = (ch0 & 0xF) + (ch0 >> 6) | ((ch0 >> 3) & 0x8);
                        uint8_t nib1 = (ch1 & 0xF) + (ch1 >> 6) | ((ch1 >> 3) & 0x8);
                        out[i] = (nib0 << 4) | nib1;
                    }
                    return out_len;
                }
                

                用法:

                unsigned char result[128];
                memset(result, 0, 128); // optional
                printf("result len=%d\n", hexStr2Arr(result, "0a0B10"));  // result = [0A 0B 10 00 00 ...]
                
                memset(result, 0, 128); // optional
                // only convert single number
                printf("result len=%d\n", hexStr2Arr(result, "0a0B10", 1)); // result = [0A 00 00 00 00 ...]
                

                【讨论】:

                  【解决方案15】:

                  没有。但是在循环中使用sscanf 相对来说比较简单。

                  【讨论】:

                  • 在 SO 上询问的任何内容都不应在响应中包含“微不足道”,否则问题将无法存在
                  • 而奥利弗显然不知道,否则他会在答案中发布“微不足道”的循环:)
                  【解决方案16】:

                  试试下面的代码:

                  static unsigned char ascii2byte(char *val)
                  {
                      unsigned char temp = *val;
                  
                      if(temp > 0x60) temp -= 39;  // convert chars a-f
                      temp -= 48;  // convert chars 0-9
                      temp *= 16;
                  
                      temp += *(val+1);
                      if(*(val+1) > 0x60) temp -= 39;  // convert chars a-f
                      temp -= 48;  // convert chars 0-9   
                  
                      return temp;
                  
                  }
                  

                  【讨论】:

                    【解决方案17】:

                    这是我的版本:

                    /* Convert a hex char digit to its integer value. */
                    int hexDigitToInt(char digit) {
                        digit = tolower(digit);
                        if ('0' <= digit && digit <= '9') //if it's decimal
                            return (int)(digit - '0');
                        else if ('a' <= digit && digit <= 'f') //if it's abcdef
                            return (int)(digit - ('a' - 10));
                        else
                            return -1; //value not in [0-9][a-f] range
                    }
                    
                    /* Decode a hex string. */
                    char *decodeHexString(const char *hexStr) {
                        char* decoded = malloc(strlen(hexStr)/2+1);
                        char* hexStrPtr = (char *)hexStr;
                        char* decodedPtr = decoded;
                    
                        while (*hexStrPtr != '\0') { /* Step through hexStr, two chars at a time. */
                            *decodedPtr = 16 * hexDigitToInt(*hexStrPtr) + hexDigitToInt(*(hexStrPtr+1));
                            hexStrPtr += 2;
                            decodedPtr++;
                        }
                    
                        *decodedPtr = '\0'; /* final null char */
                        return decoded;
                    }
                    

                    【讨论】:

                    • 你在*(decodedPtr+1) = '\0' 中有一个可爱的非一错误(因为decodedPtr 在最后一次写入后已经递增)
                    【解决方案18】:

                    能不能简单点?!

                    uint8_t hex(char ch) {
                        uint8_t r = (ch > 57) ? (ch - 55) : (ch - 48);
                        return r & 0x0F;
                    }
                    
                    int to_byte_array(const char *in, size_t in_size, uint8_t *out) {
                        int count = 0;
                        if (in_size % 2) {
                            while (*in && out) {
                                *out = hex(*in++);
                                if (!*in)
                                    return count;
                                *out = (*out << 4) | hex(*in++);
                                *out++;
                                count++;
                            }
                            return count;
                        } else {
                            while (*in && out) {
                                *out++ = (hex(*in++) << 4) | hex(*in++);
                                count++;
                            }
                            return count;
                        }
                    }
                    
                    int main() {
                        char hex_in[] = "deadbeef10203040b00b1e50";
                        uint8_t out[32];
                        int res = to_byte_array(hex_in, sizeof(hex_in) - 1, out);
                    
                        for (size_t i = 0; i < res; i++)
                            printf("%02x ", out[i]);
                    
                        printf("\n");
                        system("pause");
                        return 0;
                    }
                    

                    【讨论】:

                      【解决方案19】:

                      我知道的最好方法:

                      int hex2bin_by_zibri(char *source_str, char *dest_buffer)
                      {
                        char *line = source_str;
                        char *data = line;
                        int offset;
                        int read_byte;
                        int data_len = 0;
                      
                        while (sscanf(data, " %02x%n", &read_byte, &offset) == 1) {
                          dest_buffer[data_len++] = read_byte;
                          data += offset;
                        }
                        return data_len;
                      }
                      

                      函数返回保存在dest_buffer中的转换字节数。 输入字符串可以包含空格和混合大小写字母。

                      "01 02 03 04 ab Cd eF 垃圾 AB"

                      转换为 dest_buffer 包含 01 02 03 04 ab cd ef

                      还有 "01020304abCdeFgarbageAB"

                      像以前一样翻译。

                      解析在第一个“错误”处停止。

                      【讨论】:

                        【解决方案20】:

                        这里有一个处理文件的方案,可能用得比较频繁……

                        int convert(char *infile, char *outfile) {
                        
                        char *source = NULL;
                        FILE *fp = fopen(infile, "r");
                        long bufsize;
                        if (fp != NULL) {
                            /* Go to the end of the file. */
                            if (fseek(fp, 0L, SEEK_END) == 0) {
                                /* Get the size of the file. */
                                bufsize = ftell(fp);
                                if (bufsize == -1) { /* Error */ }
                        
                                /* Allocate our buffer to that size. */
                                source = malloc(sizeof(char) * (bufsize + 1));
                        
                                /* Go back to the start of the file. */
                                if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
                        
                                /* Read the entire file into memory. */
                                size_t newLen = fread(source, sizeof(char), bufsize, fp);
                                if ( ferror( fp ) != 0 ) {
                                    fputs("Error reading file", stderr);
                                } else {
                                    source[newLen++] = '\0'; /* Just to be safe. */
                                }
                            }
                            fclose(fp);
                        }
                             
                        int sourceLen = bufsize - 1;
                        int destLen = sourceLen/2;
                        unsigned char* dest = malloc(destLen);
                        short i;  
                        unsigned char highByte, lowByte;  
                              
                        for (i = 0; i < sourceLen; i += 2)  
                        {  
                                highByte = toupper(source[i]);  
                                lowByte  = toupper(source[i + 1]);  
                          
                                if (highByte > 0x39)  
                                    highByte -= 0x37;  
                                else  
                                    highByte -= 0x30;  
                          
                                if (lowByte > 0x39)  
                                    lowByte -= 0x37;  
                                else  
                                    lowByte -= 0x30;  
                          
                                dest[i / 2] = (highByte << 4) | lowByte;  
                        }  
                                
                        
                        FILE *fop = fopen(outfile, "w");
                        if (fop == NULL) return 1;
                        fwrite(dest, 1, destLen, fop);
                        fclose(fop);
                        free(source);
                        free(dest);
                        return 0;
                        }  
                        

                        【讨论】:

                          猜你喜欢
                          • 2011-10-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2013-08-09
                          • 2013-10-13
                          相关资源
                          最近更新 更多