如何在C中将十六进制字符串转换为二进制字符串

如何在C中将十六进制字符串转换为二进制字符串,c,binary,hex,C,Binary,Hex,我有一个十六进制值的文本文件。现在我需要将十六进制值转换为二进制,并需要将其保存到另一个文件中。 但是我不知道如何将十六进制值转换成二进制字符串! 请帮忙……这真的很容易,因为翻译是一位数一位数地进行的 0 - 0000 1 - 0001 2 - 0010 3 - 0011 4 - 0100 5 - 0101 6 - 0110 7 - 0111 8 - 1000 9 - 1001 A - 1010 B - 1011 C - 1100 D - 1101 E - 1110 F - 1111 因此,

我有一个十六进制值的文本文件。现在我需要将十六进制值转换为二进制,并需要将其保存到另一个文件中。 但是我不知道如何将十六进制值转换成二进制字符串!
请帮忙……

这真的很容易,因为翻译是一位数一位数地进行的

0 - 0000
1 - 0001
2 - 0010
3 - 0011
4 - 0100
5 - 0101
6 - 0110
7 - 0111
8 - 1000
9 - 1001
A - 1010
B - 1011
C - 1100
D - 1101
E - 1110
F - 1111

因此,例如,十六进制数FE2F8将是二进制的
1111111 0001011111000
,最快和最简单的方法是读取十六进制文件,对于读取的每个字符('0'到'F'),对等效的(0到15)二进制值进行查表。和以往一样,还有更优雅的方式,但这非常简单,可能类似于:

switch (charval) {
  case '0': binval = 0;
  case '1': binval = 1;
  case '2': binval = 2;
  case '3': binval = 3;
   ....
  case 'a': binval = 10;
  case 'b': binval = 11;
  case 'A': binval = 10;
  case 'B': binval = 11;
  ....
  case 'f':  binval = 15;
  case 'F':  binval = 15;
  default:   binval = -1;  // error case
}

现在,您必须使用移位和IOR/ADD来从这些单独的4位二进制值构造您想要的大小的字。

这是我将十六进制转换为二进制的功能,一个字节一个字节

const char input[] = "..."; // the value to be converted
char res[9]; // the length of the output string has to be n+1 where n is the number of binary digits to show, in this case 8
res[8] = '\0';
int t = 128; // set this to s^(n-1) where n is the number of binary digits to show, in this case 8
int v = strtol(input, 0, 16); // convert the hex value to a number

while(t) // loop till we're done
{
    strcat(res, t < v ? "1" : "0");
    if(t < v)
        v -= t;
    t /= 2;
}
// res now contains the binary representation of the number
void HexToBin(char hex_number, char* bit_number) {
    int max = 128;
    for(int i = 7 ; i >-1 ; i--){
        bit_number [i] = (hex_number & max ) ? 1 : 0;
        max >>=1;
    }
}
以及对函数的调用:

void main (void){

    char hex_number = 0x6E; //0110 1110
    char bit_number[8]={0,0,0,0,0,0,0,0};
    HexToBin(hex_number,bit_number);

    for(int i = 7 ; i >-1 ; i--)
        printf("%d",bit_number[i]);

    printf("\n");
    system("pause");
}
以下是MSDO的答案:

01101110

Press a key to continue . . .
很简单

#包括
#include <stdio.h>

int main()
{
    long int binaryNumber,
             hexadecimalNumber = 0,
             j = 1,
             remainder;

    printf("Enter any number any binary number: ");
    scanf("%ld", &binaryNumber);

    while(binaryNumber != 0) {
        remainder = binaryNumber % 10;
        hexadecimalNumber = hexadecimalNumber + remainder * j;
        j = j * 2;
        binaryNumber = binaryNumber / 10;
    }
    printf("Equivalent hexadecimal value: %X", hexadecimalNumber);
    return 0;
}
int main() { 长整数二进制数, 十六进制数=0, j=1, 剩余的; printf(“输入任何数字或二进制数字:”); scanf(“%ld”&二进制数); while(二进制数!=0){ 余数=二进制数%10; 十六进制数=十六进制数+余数*j; j=j*2; binaryNumber=binaryNumber/10; } printf(“等效十六进制值:%X”,十六进制数); 返回0; }
解决这个问题的方法有很多,可以使用一些算法将ascii字符范围0-9和a-f(或a-f)转换为二进制。我想找到一个只使用查找表和基准的解决方案,而不是使用算术的解决方案。更糟糕的是,上面的答案没有一个实现纯算术解决方案,有些答案甚至假设“转换为二进制”意味着转换为ascii字符串“0”和“1”

让我们先做一些设置。首先,我们希望将整个测试数据存储在内存中,以避免磁盘I/O影响测试。下面是我如何使用104857600字节(约105MB)的字符数组“testdata”创建一个标头。因为问题是如何转换文件,我们的实现应该在大数据上快速

$ { printf "char *testdata =\""; cat /dev/urandom \
    | tr -d -c "0123456789abcdefABCDEF" \
    | dd count=100 iflag=fullblock bs=1M; printf "\";\n" } > testdata.h
接下来,我们创建查找表。我认为有两种可能的方法可以通过查找表来解决这个问题。查找表将单个ascii十六进制字符映射到半字节,或者将两个十六进制字符映射到一个全字节。在前一种情况下,查找表必须有256个条目。在后一种情况下,查找表必须有256*256=65536个条目。我们可以通过意识到第一个字节的第一位永远不会被使用来减少后一个字节的大小。因此,我们只需要128*256=32768个条目的查找表。由于该解决方案还需要额外的计算步骤(应用位掩码),我们将对这两个步骤进行基准测试。我们最终得到以下测试用例:

  • 算术解
  • 256项查找表
  • 32768项查找表
  • 65536条目查找表
  • 使用一些python很容易生成第一个查找表:

    #!/usr/bin/env python
    
    import sys,struct
    
    sys.stdout.write("unsigned char base16_decoding_table1[256] = {\n")
    
    for i in xrange(256):
        try:
            j = str(int(chr(i), 16))
        except:
            j = '0'
        sys.stdout.write(j+',')
    sys.stdout.write("};\n")
    
    sys.stdout.write("\n")
    
    l = 128*256*["0"]
    
    for a in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']:
        for b in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']:
            l[struct.unpack("<H", a+b)[0]] = str(int(a+b, 16))
    
    line = "unsigned char base16_decoding_table2[%d] = {"%(128*256)
    
    for e in l:
        line += e+","
        if len(line) > 70:
            sys.stdout.write(line+"\n")
            line = ""
    sys.stdout.write(line+"};\n")
    
    sys.stdout.write("\n")
    
    l = 256*256*["0"]
    
    for a in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']:
        for b in ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F']:
            l[struct.unpack("<H", a+b)[0]] = str(int(a+b, 16))
    
    line = "unsigned char base16_decoding_table3[%d] = {"%(256*256)
    
    for e in l:
        line += e+","
        if len(line) > 70:
            sys.stdout.write(line+"\n")
            line = ""
    sys.stdout.write(line+"};\n")
    
    现在我们可以编写一些C代码进行测试

    #include <stdio.h>
    #include <time.h>
    #include <inttypes.h>
    
    #include "testdata.h"
    #include "base16_decoding_table.h"
    
    #define TESTDATALEN 104857600
    
    /* the resulting binary string is half the size of the input hex string
     * because every two hex characters map to one byte */
    unsigned char result[TESTDATALEN/2];
    
    void test1()
    {
        size_t i;
        char cur;
        unsigned char val;
        for (i = 0; i < TESTDATALEN; i++) {
            cur = testdata[i];
            if (cur >= 97) {
                val = cur - 97 + 10;
            } else if (cur >= 65) {
                val = cur - 65 + 10;
            } else {
                val = cur - 48;
            }
            /* even characters are the first half, odd characters the second half
             * of the current output byte */
            if (i%2 == 0) {
                result[i/2] = val << 4;
            } else {
                result[i/2] |= val;
            }
        }
    }
    
    void test2()
    {
        size_t i;
        char cur;
        unsigned char val;
        for (i = 0; i < TESTDATALEN; i++) {
            cur = testdata[i];
            val = base16_decoding_table1[(int)cur];
            /* even characters are the first half, odd characters the second half
             * of the current output byte */
            if (i%2 == 0) {
                result[i/2] = val << 4;
            } else {
                result[i/2] |= val;
            }
        }
    }
    
    void test3()
    {
        size_t i;
        uint16_t *cur;
        unsigned char val;
        for (i = 0; i < TESTDATALEN; i+=2) {
            cur = (uint16_t*)(testdata+i);
            // apply bitmask to make sure that the first bit is zero
            val = base16_decoding_table2[*cur & 0x7fff];
            result[i/2] = val;
        }
    }
    
    void test4()
    {
        size_t i;
        uint16_t *cur;
        unsigned char val;
        for (i = 0; i < TESTDATALEN; i+=2) {
            cur = (uint16_t*)(testdata+i);
            val = base16_decoding_table3[*cur];
            result[i/2] = val;
        }
    }
    
    #define NUMTESTS 1000
    
    int main() {
        struct timespec before, after;
        unsigned long long checksum;
        int i;
        double elapsed;
    
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NUMTESTS; i++) {
            test1();
        }
        clock_gettime(CLOCK_MONOTONIC, &after);
    
        checksum = 0;
        for (i = 0; i < TESTDATALEN/2; i++) {
            checksum += result[i];
        }
        printf("checksum: %llu\n", checksum);
        elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
        printf("arithmetic solution took %f seconds\n", elapsed);
    
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NUMTESTS; i++) {
            test2();
        }
        clock_gettime(CLOCK_MONOTONIC, &after);
    
        checksum = 0;
        for (i = 0; i < TESTDATALEN/2; i++) {
            checksum += result[i];
        }
        printf("checksum: %llu\n", checksum);
        elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
        printf("256 entries table took %f seconds\n", elapsed);
    
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NUMTESTS; i++) {
            test3();
        }
        clock_gettime(CLOCK_MONOTONIC, &after);
    
        checksum = 0;
        for (i = 0; i < TESTDATALEN/2; i++) {
            checksum += result[i];
        }
        printf("checksum: %llu\n", checksum);
        elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
        printf("32768 entries table took %f seconds\n", elapsed);
    
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NUMTESTS; i++) {
            test4();
        }
        clock_gettime(CLOCK_MONOTONIC, &after);
    
        checksum = 0;
        for (i = 0; i < TESTDATALEN/2; i++) {
            checksum += result[i];
        }
        printf("checksum: %llu\n", checksum);
        elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
        printf("65536 entries table took %f seconds\n", elapsed);
    
        return 0;
    }
    
    然后运行它:

    $ ./a.out
    
    结果是:

  • 算术解:437.17秒
  • 256项查找表:117.80s
  • 32768项查找表:52.33 s
  • 65536条目查找表:44.66 s

  • 我们可以得出这样的结论:查找表在任何时候都优于算术解,为更大的查找表浪费内存可能值得额外的运行时间。

    这样,您将获得十六进制数字的数值,但无法获得二进制表示。此外,要进行这样的查找,我要么使用固定字符串(
    0123456789abcdef
    ),然后使用
    strchr()
    获取数字的值,要么使用数组
    char[256]
    并使用字符/数字作为索引。这样,您就可以使用二进制表示法来表示数字作为值,并跳过额外的转换。这不是表查找。表查找应该是O(1),但您的解决方案使用的查找是O(N)?我相信你指的不是价值而是表现:价值观是一样的,不管它们是如何表现的。@pmg:ya我在做一些类似于家庭作业的事情。实际上,我将一个图像文件转换为十六进制文件。现在我需要从那个十六进制文件中创建图像。@StanlyMoses:在将其作为副本关闭之前,请仔细阅读问题,这个问题询问如何将十六进制转换为二进制,另一个问题询问如何将二进制转换为十六进制。答案1的编译版本以ascii打印1和0。这是如何将十六进制转换成二进制的?@OuwenHuang你确定你的
    数字是正确的吗?或者你是什么时候出错的?这里需要帮助。答案的试用版本2逐字逐句,strcat根本没有填充res数组,它始终保持在\0。@sce很难猜测。只需创建您自己的问题并链接此答案以供参考。第二个解决方案究竟应该如何工作?v[0]是字符,或者数字上是ascii值,因此如果v[0]=f,则二进制的索引是102,而不是15。至少看起来是这样,因为这对我来说是一个错误。无法使第二个解决方案起作用,但起作用的是
    long v=strtol({input[p++],0},NULL,16);strcat(res,二进制[v])怎么可能更多的条目有更少的基准测试时间?@Zimano因为更大的查找表意味着更多的查找和更少的算术运算哦,我明白了。那真的很有趣,谢谢!虽然此代码可能会回答该问题,但提供有关此代码为什么和/或如何回答该问题的附加上下文可提高其长期价值。
    
    void printBin(unsigned int num){
      char str[sizeof(num)*8];
      char *p = str;
      for(*p='0'; num; num/=2) { *p++='0'+num%2; } //store remainders
      for(--p; p>=str; putchar(*p--)) {;}          //print remainders in reverse
      putchar('\n');
    }
    
    #include <stdio.h>
    #include <time.h>
    #include <inttypes.h>
    
    #include "testdata.h"
    #include "base16_decoding_table.h"
    
    #define TESTDATALEN 104857600
    
    /* the resulting binary string is half the size of the input hex string
     * because every two hex characters map to one byte */
    unsigned char result[TESTDATALEN/2];
    
    void test1()
    {
        size_t i;
        char cur;
        unsigned char val;
        for (i = 0; i < TESTDATALEN; i++) {
            cur = testdata[i];
            if (cur >= 97) {
                val = cur - 97 + 10;
            } else if (cur >= 65) {
                val = cur - 65 + 10;
            } else {
                val = cur - 48;
            }
            /* even characters are the first half, odd characters the second half
             * of the current output byte */
            if (i%2 == 0) {
                result[i/2] = val << 4;
            } else {
                result[i/2] |= val;
            }
        }
    }
    
    void test2()
    {
        size_t i;
        char cur;
        unsigned char val;
        for (i = 0; i < TESTDATALEN; i++) {
            cur = testdata[i];
            val = base16_decoding_table1[(int)cur];
            /* even characters are the first half, odd characters the second half
             * of the current output byte */
            if (i%2 == 0) {
                result[i/2] = val << 4;
            } else {
                result[i/2] |= val;
            }
        }
    }
    
    void test3()
    {
        size_t i;
        uint16_t *cur;
        unsigned char val;
        for (i = 0; i < TESTDATALEN; i+=2) {
            cur = (uint16_t*)(testdata+i);
            // apply bitmask to make sure that the first bit is zero
            val = base16_decoding_table2[*cur & 0x7fff];
            result[i/2] = val;
        }
    }
    
    void test4()
    {
        size_t i;
        uint16_t *cur;
        unsigned char val;
        for (i = 0; i < TESTDATALEN; i+=2) {
            cur = (uint16_t*)(testdata+i);
            val = base16_decoding_table3[*cur];
            result[i/2] = val;
        }
    }
    
    #define NUMTESTS 1000
    
    int main() {
        struct timespec before, after;
        unsigned long long checksum;
        int i;
        double elapsed;
    
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NUMTESTS; i++) {
            test1();
        }
        clock_gettime(CLOCK_MONOTONIC, &after);
    
        checksum = 0;
        for (i = 0; i < TESTDATALEN/2; i++) {
            checksum += result[i];
        }
        printf("checksum: %llu\n", checksum);
        elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
        printf("arithmetic solution took %f seconds\n", elapsed);
    
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NUMTESTS; i++) {
            test2();
        }
        clock_gettime(CLOCK_MONOTONIC, &after);
    
        checksum = 0;
        for (i = 0; i < TESTDATALEN/2; i++) {
            checksum += result[i];
        }
        printf("checksum: %llu\n", checksum);
        elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
        printf("256 entries table took %f seconds\n", elapsed);
    
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NUMTESTS; i++) {
            test3();
        }
        clock_gettime(CLOCK_MONOTONIC, &after);
    
        checksum = 0;
        for (i = 0; i < TESTDATALEN/2; i++) {
            checksum += result[i];
        }
        printf("checksum: %llu\n", checksum);
        elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
        printf("32768 entries table took %f seconds\n", elapsed);
    
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NUMTESTS; i++) {
            test4();
        }
        clock_gettime(CLOCK_MONOTONIC, &after);
    
        checksum = 0;
        for (i = 0; i < TESTDATALEN/2; i++) {
            checksum += result[i];
        }
        printf("checksum: %llu\n", checksum);
        elapsed = difftime(after.tv_sec, before.tv_sec) + (after.tv_nsec - before.tv_nsec)/1.0e9;
        printf("65536 entries table took %f seconds\n", elapsed);
    
        return 0;
    }
    
    $ gcc -O3 -g -Wall -Wextra test.c
    
    $ ./a.out
    
    void printBin(unsigned int num){
      char str[sizeof(num)*8];
      char *p = str;
      for(*p='0'; num; num/=2) { *p++='0'+num%2; } //store remainders
      for(--p; p>=str; putchar(*p--)) {;}          //print remainders in reverse
      putchar('\n');
    }