-1

I asked a question few days ago and it helped me quite a bit but yet I have a question again. What I don't get is when I get hexadecimal input as scanf("%c%c.%c%c.%c%c.%c%c%c") how do I convert this to binary as it is. What I'm trying to say is let's say I get input as 00.11.10.FF how do I convert it to 00000000.00010001.00010000.11111111 and print it like this.

I will be glad if you help me.

Kaya
  • 21
  • 6
  • Hex -> binary is extremely simple. Every hex digit turns into exactly 4 binary bits. – Ben Voigt Mar 17 '19 at 02:16
  • So I basically take every variable and convert them. But that would require tons of if statements right? – Kaya Mar 17 '19 at 02:20
  • First you understand when you are reading `"%c%c...."` you are reading ASCII characters and not numbers, so you first must convert between the ASCII character `[0-9A-F]` to the corresponding *numeric value*. Once you have the decimal representation -- the binary is already what is stored in memory. Alternatively, you can write a *lookup-table* to go directly from ASCII to binary representation of that character -- up to you. – David C. Rankin Mar 17 '19 at 02:21
  • Possible duplicate of [how to get multiple character in one input in C](https://stackoverflow.com/questions/55201616/how-to-get-multiple-character-in-one-input-in-c) – Chris Taylor Mar 17 '19 at 04:46

1 Answers1

2

If you are still having problems, as explained in the comments, unless you want to create a lookup-table (which is a fine way to go), your first task is to convert the ASCII characters "00.11.10.FF" into actual numeric values of 0x0, 0x11, 0x10 & 0xff. There are a number of ways to do this, but if you are reading with scanf, you may as well let scanf do it for you by reading with the "%x" format specifier which will accept the hex-characters and perform the conversion.

For example, to read each of the quads into an array of unsigned values named hex, you could do:

#define QUAD  4u    /* if you need a constant, #define one (or more) */
...
    unsigned hex[QUAD] = {0};   /* let's input the values as numbers */
    ...
    if (scanf ("%x.%x.%x.%x", &hex[0], &hex[1], &hex[2], &hex[3]) != 4) {
        fputs ("error: invalid input.\n", stderr);
        return 1;
    }

(note: you could declare hex as unsigned char and save the additional bytes, but then you would want to limit the value read by scanf using the hh type-modifier, e.g. "%hhx", but that prefix isn't supported on older versions of VS, so in this case a simple unsigned is used instead)

With the hex-characters converted to numeric values, all that remains is outputting the binary-representation of each (i.e. the value that is already stored in memory). To do so, you can simply loop and shift, checking whether the bit is a 0 or 1 and outputting the corresponding character '0' or '1'.

Additionally, since a simple loop and shift will only output until there are no more 1's bits left, you will want to set the number of bits to display to make sure you get a full 8-per-byte by looping that number of times. A handy function to write the information to stdout for the number of bits requested can be:

/** binary representation of 'v' padded to 'sz' bits.
 *  the padding amount is limited to the number of
 *  bits in 'v'. valid range: 1 - sizeof v * CHAR_BIT.
 */
void binprnpad (const unsigned long v, size_t sz)
{
    if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
    if (!v)  { while (sz--) putchar ('0'); return; }

    if (sz > sizeof v * CHAR_BIT)
        sz = sizeof v * CHAR_BIT;

    while (sz--)
        putchar ((v >> sz & 1) ? '1' : '0');
}

(CHAR_BIT is a macro representing the number of bits-per-byte and is found in limits.h)

Putting it altogether, you could do:

#include <stdio.h>
#include <limits.h>

#define QUAD  4u    /* if you need a constant, #define one (or more) */
#define QBITS 8u

/** binary representation of 'v' padded to 'sz' bits.
 *  the padding amount is limited to the number of
 *  bits in 'v'. valid range: 0 - sizeof v * CHAR_BIT.
 */
void binprnpad (const unsigned long v, size_t sz)
{
    if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
    if (!v)  { while (sz--) putchar ('0'); return; }

    if (sz > sizeof v * CHAR_BIT)
        sz = sizeof v * CHAR_BIT;

    while (sz--)
        putchar ((v >> sz & 1) ? '1' : '0');
}

int main (void) {

    unsigned hex[QUAD] = {0};   /* let's input the values as numbers */

    fputs ("enter hex IP: ", stdout);   /* read/validate input */
    if (scanf ("%x.%x.%x.%x", &hex[0], &hex[1], &hex[2], &hex[3]) != 4) {
        fputs ("error: invalid input.\n", stderr);
        return 1;
    }

    for (unsigned i = 0; i < QUAD; i++) {   /* loop over each quad */
        if (i)                      /* if not zero output the '.' */
            putchar ('.');
        binprnpad (hex[i], QBITS);  /* output the 8-bits per quad */
    }
    putchar ('\n');     /* tidy up with newline */

    return 0;
}

Example Use/Output

$ ./bin/hexip2bin
enter hex IP: 00.11.10.FF
00000000.00010001.00010000.11111111

Reading Only Characters -- The Lookup Table Approach

If you can only read characters and cannot read into an array or string, then the simplest approach is to simply read a characters and lookup what its binary representation would be from a simply table that holds the binary representations for 0 - 15 (or [0-9A-F] in other words).

The lookup table can be a simple global, e.g.

/* lookup table for hex byte binary representations */
char *lookup[] = {  "0000", "0001", "0010", "0011", 
                    "0100", "0101", "0110", "0111", 
                    "1000", "1001", "1010", "1011",
                    "1100", "1101", "1110", "1111"  };

The scheme is then straight forward, read a character from the user, if the character c is 0-9, just output lookup[c - '0'] (where c - '0' results in the number 0-9 See: ASCIITable.com). If the character c is [A-F] then output lookup[c - '7'] (which subtracts the ASCII character value of '7' to index 10-15 in the lookup table). Otherwise, if the character is a '.', just output it unchanged.

To protect against someone entering "00.11.10.ff", just convert all characters read to uppper-case with toupper() provided in ctype.h (or clear the 6th bit in all [a-f] manually).

That's as simple as it gets. You don't even need scanf, just getchar();, e.g.

#include <stdio.h>
#include <ctype.h>

#define QBYTES 8u   /* if you need a constant, #define one */

/* lookup table for hex byte binary representations */
char *lookup[] = {  "0000", "0001", "0010", "0011", 
                    "0100", "0101", "0110", "0111", 
                    "1000", "1001", "1010", "1011",
                    "1100", "1101", "1110", "1111"  };
int main (void) {

    unsigned ndx = 0;   /* index of the hex byte read */

    fputs ("enter hex IP: ", stdout);   /* read/validate input */

    while (ndx < QBYTES) {  /* read until 8 hex bytes read */
        unsigned char c = toupper(getchar());   /* read char as upper-case */
        if (isdigit (c)) {                      /* if [0-9] */
            fputs (lookup[c - '0'], stdout);
            ndx++;  /* increment index */
        }
        else if (isxdigit (c)) {                /* if [A-F] */
            fputs (lookup[c - '7'], stdout);
            ndx++;
        }
        else if (c == '.')                      /* if '.' */
            putchar (c);
        else {      /* handle character not [0-9A-F.] */
            fputs ("(error: invalid character input)\n", stderr);
            break;
        }
    }
    putchar ('\n');     /* tidy up with newline */

    return 0;
}

Example Use/Output

$ ./bin/hexip2bin
enter hex IP: 00.11.10.FF
00000000.00010001.00010000.11111111

lower-case hex example:

$ ./bin/hexip2bin
enter hex IP: 00.11.10.ff
00000000.00010001.00010000.11111111

Read A char Output A Nibble

And, of course, you can always mix and match between the methods. If you can't use a lookup-table, then just get the numeric value of the character and write the 4-bits representing that hex value as output, e.g.

#include <stdio.h>
#include <limits.h>
#include <ctype.h>

#define QUAD  4u    /* if you need a constant, #define one (or more) */
#define QBYTES 8u

/** binary representation of 'v' padded to 'sz' bits.
 *  the padding amount is limited to the number of
 *  bits in 'v'. valid range: 1 - sizeof v * CHAR_BIT.
 */
void binprnpad (const unsigned long v, size_t sz)
{
    if (!sz) { fprintf (stderr, "error: invalid sz.\n"); return; }
    if (!v)  { while (sz--) putchar ('0'); return; }

    if (sz > sizeof v * CHAR_BIT)
        sz = sizeof v * CHAR_BIT;

    while (sz--)
        putchar ((v >> sz & 1) ? '1' : '0');
}

int main (void) {

    unsigned ndx = 0;   /* index of the hex byte read */

    fputs ("enter hex IP: ", stdout);   /* read/validate input */

    while (ndx < QBYTES) {  /* read until 8 hex bytes read */
        unsigned char c = toupper(getchar());   /* read char as upper-case */
        if (isdigit (c)) {                      /* if [0-9] */
            binprnpad (c - '0', QUAD);
            ndx++;
        }
        else if (isxdigit (c)) {                /* if [A-F] */
            binprnpad (c - '7', QUAD);
            ndx++;
        }
        else if (c == '.')                      /* if '.' */
            putchar (c);
        else {      /* handle character not [0-9A-F.] */
            fputs ("(error: invalid character input)\n", stderr);
            break;
        }
    }
    putchar ('\n');     /* tidy up with newline */

    return 0;
}

(output is the same)

Just another way of skinning the same cat. Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Hey, thank you for your answer! But the thing is I don't quite know them as we didn't learn them yet. The reason I am using %c to take input is because the instructor said we can't use %x, arrays to store values and strings as I said because we didn't learn them yet. This is my first year in computer engineering and this is for an assignment of c programming language. I apologize, should've wrote it in the main post. – Kaya Mar 17 '19 at 03:04
  • Ok, I can help you out there, I'll drop an addition. (and you should slap your professor for the additional needless work `:)` – David C. Rankin Mar 17 '19 at 03:05
  • Thank you for explaining in such detail. This is going to be really helpful for me. Although I can't use that code fully I will modify it a bit to not break the rules. The professor says this will be helpful in the future but I really can't see myself working on a project and not using %x. Anyway thanks again! – Kaya Mar 17 '19 at 10:38