【问题标题】:Converting large bit strings to hexadecimal in C在C中将大位字符串转换为十六进制
【发布时间】:2021-11-13 11:44:57
【问题描述】:

我需要像这样转换大位字符串:

unsigned char* key = "0111010111010101010101010100101011010";

转成这样的十六进制字符串:

unsigned char* string = EBAAAA95A;

问题是我的密钥通常超过 50 或 60 位,当我尝试使用 strtoll(key, NULL, 2) 转换它们时,返回的数字远远大于 long long int 甚至可以容纳的数字。有没有一种直接将其转换为十六进制的有效方法?

非常感谢您的帮助!

【问题讨论】:

  • 不要使用数字将位转换为十六进制。它们只是字符串。计算位数,以便您可以从右侧开始将它们分成四组,然后将每四组(或一对四的初始组)转换为一个十六进制数字。
  • 您可以将字符串分成更小的数字并单独解析它们。 Here's an example I just hacked together that reads the string nibble-by-nibble。我不会将它作为答案发布,因为我对它并不完全满意(源字符串的长度必须是 4 的倍数,不验证源字符串),但是是的,这只是一个示例。
  • @mediocrevegetable1 我做了something similar,但改用了一张桌子。我们的两种解决方案都存在相同的问题,即输入必须是 4 的倍数,否则会导致 UB。
  • 即使产品/库推荐偏离主题:en.wikipedia.org/wiki/…
  • 如果位串不是四的精确倍数,则在开头添加 0、00 或 000 以给出十六进制数字的确切数量。

标签: c binary cryptography hex ansi


【解决方案1】:

我认为您需要推出自己的实施。这是一个从@mediocrevegetable 中获得灵感的实现

#include <stdlib.h>
#include <string.h>

static inline int bitstr_to_int(const char *str, int len)
{
        int h = 0;
        for (int i = 0; i < len; i++) {
                switch (str[i]) {
                        case '0': h *= 2; continue;
                        case '1': h *= 2; h++; continue;
                        default: return -1;
                }
        }
        return h;
}

char * bitstr_to_hexstr(const char *str, int len)
{
        static const char hex_digit[] = {
                '0', '1', '2', '3',
                '4', '5', '6', '7',
                '8', '9', 'A', 'B',
                'C', 'D', 'E', 'F'
        };

        int i = 0; //traces the input chars in bitstr
        int j = 0; //traces the output chars in hexstr
        int h = 0;
        int r = len % 4;
        int q = len / 4;

        char *hexstr = malloc(q + !!r + 1);
        if (hexstr == NULL) return NULL;

        if (r != 0) {
                h = bitstr_to_int(str, r);
                if (h == -1) goto err;
                hexstr[j++] = hex_digit[h];
        }

        for (i = r; i < len; i += 4) {
                h = bitstr_to_int(str+i, 4);
                if (h == -1) goto err;
                hexstr[j++] = hex_digit[h];
        }

        hexstr[j] = '\0';
        return hexstr;
err:
        free(hexstr);
        return NULL;
}

int main(void)
{
    const char *key = "0111010111010101010101010100101011010";

    char *res = bitstr_to_hexstr(key, strlen(key));
    printf("%s\n", res);
}

【讨论】:

    【解决方案2】:

    如果您需要处理大数字,一个好的库(也许是首选库)是GMP。这是一个简单的示例,展示了您询问的转换:

    #include <stdio.h>
    #include <gmp.h>
    
    int main()
    {
        char *instr = "0111010111010101010101010100101011010";
        char outstr[100];
        mpz_t x;
        mpz_init(x);
        mpz_set_str(x, instr, 2);                     /* convert from base 2 */
        printf("%s\n", mpz_get_str(outstr, 16, x));   /* convert to base 16 */
    }
    

    【讨论】:

      【解决方案3】:

      如果字符串长度超过 64 位,您可以一次转换一个十六进制数字,确保只有第一个数字使用少于 4 位。

      这是一个带有测试用例的实现:

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      /* convert len bits to a number */
      static unsigned bin2hex_val(const char *str, size_t len) {
          unsigned v = 0;
          while (len --> 0) {
              v = v * 2 + (*str++ - '0');
          }
          return v;
      }
      
      char *bin2hex_str(const char *str) {
          static const char hex_digits[16] = "0123456789ABCDEF";
          size_t len = strspn(str, "01"); /* number of binary digits */
          size_t hexlen = (len + 3) / 4;     /* number of hex digits */
          char *p = malloc(hexlen + 1);   /* allocate the hex string */
          size_t i = 0;
      
          if (p) {
              /* special case the first hex digit if fewer than 4 bits */
              if (len % 4) {
                  p[i++] = hex_digits[bin2hex_val(str, len % 4)];
                  str += len % 4;
                  len -= len % 4;
              }
              /* convert remaining groups of 4 bits as hex digits */
              while (len > 0) {
                  p[i++] = hex_digits[bin2hex_val(str, 4)];
                  str += 4;
                  len -= 4;
              }
              p[i] = '\0';
          }
          return p;
      }
      
      void test(const char *str) {
          char *p = bin2hex_str(str);
          printf("%s -> %s\n", str, p);
          free(p);
      }
      
      int main() {
          test("");
          test("0");
          test("1");
          test("01");
          test("011");
          test("0111");
          test("01110");
          test("011101");
          test("0111010");
          test("01110101");
          test("01110101110101010101010101001010");
          test("0111010111010101010101010100101011010011101011101010101010101010");
          test("01110101110101010101010101001010110100111010111010101010101010100101011010");
          test("ABC");
          test("0.0");
          test("123");
          return 0;
      }
      

      输出:

       ->
      0 -> 0
      1 -> 1
      01 -> 1
      011 -> 3
      0111 -> 7
      01110 -> 0E
      011101 -> 1D
      0111010 -> 3A
      01110101 -> 75
      01110101110101010101010101001010 -> 75D5554A
      0111010111010101010101010100101011010011101011101010101010101010 -> 75D5554AD3AEAAAA
      01110101110101010101010101001010110100111010111010101010101010100101011010 -> 1D755552B4EBAAAA95A
      ABC ->
      0.0 -> 0
      123 -> 1
      

      【讨论】:

        猜你喜欢
        • 2018-01-31
        • 2022-07-22
        • 2016-03-06
        • 1970-01-01
        • 2014-06-09
        • 2018-06-06
        • 1970-01-01
        • 2018-01-03
        • 2014-10-27
        相关资源
        最近更新 更多