10

I have a text file with hexadecimal values. Now I need to convert the hexadecimal value to binary and need to save it on another file. But I don't know how to convert the hexadecimal value to a binary string! Please help...

4
  • You can try it like this: johnsantic.com/comp/htoi.html Commented Dec 18, 2011 at 11:29
  • 5
    homework? And I'm sure you don't mean values but representations: the values are the same regardless of how they are represented. Commented Dec 18, 2011 at 11:29
  • 1
    @pmg:ya i was doing some thing like a home work. Actually i converted a image file to hexadecimal file. Now i need to create the image from that hexadecimal file. Commented Dec 18, 2011 at 11:36
  • 1
    @StanlyMoses: Read the questions carefully before closing it as duplicate, this ask how to convert hex to binary the other one asks how to convert binary to hex. Commented Feb 18, 2016 at 12:57

8 Answers 8

11

It's quite easy, really, because the translation goes digit-by-digit.

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

So, for example, the hex number FE2F8 will be 11111110001011111000 in binary

Sign up to request clarification or add additional context in comments.

1 Comment

They need a program to do this.
5
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

As an alternative (this assumes there's no prefix like in "0x3A"):

const char binary[16][5] = {"0000", "0001", "0010", "0011", "0100", ...};
const char digits = "0123456789abcdef";

const char input[] = "..." // input value
char res[1024];
res[0] = '\0';
int p = 0;

while(input[p])
{
    const char *v = strchr(digits, tolower(input[p++]));
    if (v)
        strcat(res, binary[v - digits]);
}
// res now contains the binary representation of the number

8 Comments

@OuwenHuang Are you sure your digits is correct? Or wher do you get that error?
Need some help here. Tried version2 of the answer verbatim and strcat is not populating the res array at all, it stays at \0 throughout.
@sce hard to guess. Just create your own question and link this answer for reference.
How exactly is that 2nd solution supposed to work? v[0] is the character, or numerically the ascii value, so if v[0] = f, then the index into binary is 102, not 15. At least that appears to be the case, because this is segfaulting on that line for me.
Couldn't get that 2nd solution to work, but what did work was long v = strtol({input[p++], 0}, NULL, 16); strcat(res, binary[v]);
|
2

There are many ways to solve this question that use some arithmetics to convert from ascii character ranges 0-9 and a-f (or A-F) to binary. I wanted to find a solution which only uses a lookup table and benchmark that against a solution that uses arithmetics instead. Strangly enough, none of the answers above implement a purely arithmetic solution and some answers even assume that "converting to binary" means converting to a ascii string of characters "0" and "1".

Lets first do some setups. Firstly, we want to have the whole test data in memory so that we avoid disk I/O influencing the test. Here is how I create a header with a character array "testdata" of 104857600 bytes, roughly 105 MB. As the question was how to convert files, our implementation should be fast on large data.

$ { printf "char *testdata =\""; cat /dev/urandom \
    | tr -d -c "0123456789abcdefABCDEF" \
    | dd count=100 iflag=fullblock bs=1M; printf "\";\n" } > testdata.h

Next, we create the lookup tables. I see two possible ways to solve this with a lookup table. Either the lookup table maps individual ascii hex characters to half bytes or it maps two hex characters to a full byte. In the former case, the lookup table has to have 256 entries. In the latter case, the lookup table has to have 256*256=65536 entries. We can reduce the size of the latter by realizing that the first bit of the first byte will never be used. So we only need a lookup table of 128*256=32768 entries. Since that solution also requires an additional calculation step (applying a bitmask) we will benchmark both. We end up with the following test cases:

  1. arithmetic solution
  2. 256 entries lookup table
  3. 32768 entries lookup table
  4. 65536 entries lookup table

The first lookup table is easy to generate using some 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")

And then:

python gen.py > base16_decoding_table.h

Now we can write some C code to test.

#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;
}

Lets compile the thing:

$ gcc -O3 -g -Wall -Wextra test.c

And run it:

$ ./a.out

The result:

  1. arithmetic solution: 437.17 s
  2. 256 entries lookup table: 117.80 s
  3. 32768 entries lookup table: 52.33 s
  4. 65536 entries lookup table: 44.66 s

This we can conclude lookup tables beat arithmetic solutions any time and that wasting memory for bigger lookup tables might be worth the additional runtime.

4 Comments

How is it possible for more entries to have less benchmarking time?
@Zimano because bigger lookup table means more lookups and less arithmetic operations
Ooh, I see. That's pretty interesting actually, thanks!
This has proved to be extremely useful. The table lookup method improved performance by 20% on a prototype of a critical program that does Hex to Binary conversion for some database data.
1
void hex_binary(char * res){
char binary[16][5] = {"0000", "0001", "0010", "0011", "0100", "0101","0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110","1111"};
char digits [] = "0123456789abcdef";

const char input[] = "a9e6"; // input value
res[0] = '\0';
int p = 0;
int value =0;
    while(input[p])
    {
        const char *v = strchr(digits, tolower(input[p]));
        if(v[0]>96){
            value=v[0]-87;
        }
        else{
            value=v[0]-48;
        }
        if (v){
            strcat(res, binary[value]);
        }
        p++;
    }
    printf("Res:%s\n", res);
}

1 Comment

Compiled Version of Answer 1
-1
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');
}

Comments

-2

The quickest and easiest way is to read the hex file and, for each character ('0' through 'F') read, do a table lookup of the equivalent (0 through 15) binary value. There are, as ever, more elegant ways but this is very straightforward, maybe something like:

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
}

Now you have to use shifts and IORs/ADDs to construct words of the size you want from these individual 4-bit binary values.

2 Comments

That way you'll get the number value of a hex digit, but you won't get the binary representation. Also, to do such a lookup, i'd either use a fixed string (0123456789abcdef) and then get the value of a digit by using strchr() on it or i'd just use an array char [256] and use the character/digit as the index. That way you could as well use the binary representation for the digits as the values and skip additional conversion.
This is not a table lookup. A table lookup would be O(1) but your solution uses lookups that are O(N).
-3

That's my function to convert HEX to BIN, byte a byte.

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;
    }
}

and the call to the function:

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");
}

And here is the MSDOS answer:

01101110

Press a key to continue . . .

Quite easy!

1 Comment

This prints ones and zeroes in ascii. How does this convert any hex to their binary representation?
-3
#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;
}

1 Comment

While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.