0

I am using the following approach to print the binary of an ascii character:

unsigned char bitmask = 0b10000000;
char _my_char = 'a';
for (int i=0; i<8; i++) {
    if (i==4) putchar(' '); // separate every four characters
    printf("%d", (_my_char & bitmask) != 0);
    bitmask = bitmask >> 1;
}
putchar('\n');
return 0;

How could I generalize this so that, for example, I could print the binary of any data type/structure? One byte per row?

  • You could package that code up as a `print_byte_in_binary()` function, then call it repeatedly for each byte of a larger data structure. You could step a byte pointer over the bytes of that larger data structure, something like `unsigned char *cp; for cp = (unsigned char *)&x; cp < (unsigned char *)&x + sizeof(x); cp++) print_byte_in_binary(*cp);` – Steve Summit Sep 04 '19 at 03:49
  • "How could I ... print the binary of any data type/structure?": [convert any variable/object to a string that encodes the binary](https://stackoverflow.com/a/35367414/2410359) may be of interest. – chux - Reinstate Monica Sep 04 '19 at 03:51
  • 1
    That binary constant `0b10000000` is a nonstandard extension of your compiler, I think. More portable would be `unsigned char bitmask = 0x80;`. – Steve Summit Sep 04 '19 at 04:04

3 Answers3

1

There are numerous ways to do this. The following outputs a nice chart of printable characters giving the value for each character in ASCII, decimal, hex and binary, e.g.

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

/* CHAR_BIT */
#ifndef CHAR_BIT
#define CHAR_BIT  8
#endif

int main (void) {

    char c = 0;     /* character */
    int i = 0;      /* int loop counter */

    printf ("\nchar |  int  |  hex   |  binary\n");
    printf ("-----+-------+--------+---------\n");
    for (c = 32; c <= 126; c++) {   /* for each char in printable range  */
        /* output the character, decimal, hex and binary */
        printf ("  %c  |  %3d  |  0x%02x  | ", c, c, c);

        for (i = sizeof (c) * CHAR_BIT - 1; i >= 0; i--)    /* for each bit */
            printf ("%d", ((c >> i) & 0x1) ? 1 : 0);        /* output 0/1 */
        putchar ('\n');                                     /* output \n */
    }

    putchar ('\n');
}

Example Use/Output

$ ./bin/bin_ascii

char |  int  |  hex   |  binary
-----+-------+--------+---------
     |   32  |  0x20  | 00100000
  !  |   33  |  0x21  | 00100001
  "  |   34  |  0x22  | 00100010
  #  |   35  |  0x23  | 00100011
  $  |   36  |  0x24  | 00100100
  %  |   37  |  0x25  | 00100101
  &  |   38  |  0x26  | 00100110
  '  |   39  |  0x27  | 00100111
  (  |   40  |  0x28  | 00101000
  )  |   41  |  0x29  | 00101001
  *  |   42  |  0x2a  | 00101010
  +  |   43  |  0x2b  | 00101011
  ,  |   44  |  0x2c  | 00101100
  -  |   45  |  0x2d  | 00101101
  .  |   46  |  0x2e  | 00101110
  /  |   47  |  0x2f  | 00101111
  0  |   48  |  0x30  | 00110000
  1  |   49  |  0x31  | 00110001
  2  |   50  |  0x32  | 00110010
  3  |   51  |  0x33  | 00110011
  4  |   52  |  0x34  | 00110100
  5  |   53  |  0x35  | 00110101
  6  |   54  |  0x36  | 00110110
  7  |   55  |  0x37  | 00110111
  8  |   56  |  0x38  | 00111000
  9  |   57  |  0x39  | 00111001
<snip>
  p  |  112  |  0x70  | 01110000
  q  |  113  |  0x71  | 01110001
  r  |  114  |  0x72  | 01110010
  s  |  115  |  0x73  | 01110011
  t  |  116  |  0x74  | 01110100
  u  |  117  |  0x75  | 01110101
  v  |  118  |  0x76  | 01110110
  w  |  119  |  0x77  | 01110111
  x  |  120  |  0x78  | 01111000
  y  |  121  |  0x79  | 01111001
  z  |  122  |  0x7a  | 01111010
  {  |  123  |  0x7b  | 01111011
  |  |  124  |  0x7c  | 01111100
  }  |  125  |  0x7d  | 01111101
  ~  |  126  |  0x7e  | 01111110

Let me know if you have any questions about the logic.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • this is such a great example and answer. Thanks for providing all the comments and the output, this is really helpful for my understand (and hopefully other beginners trying to understand something similar). –  Sep 04 '19 at 20:33
  • I'm glad it helped. I find the more I comment each line in the code, the easier it makes it for me to recall my original thought process in writing it to begin with (especially a couple of years later) *and* the easier it makes it to find errors in my logic. – David C. Rankin Sep 04 '19 at 22:08
0

You could create a function which takes a void pointer and the size of the structure as input.

void printdata(void *data, size_t len)
{
    char my_char; 
    for (size_t m = 0; m < len; m++)
    {    
        my_char = *(((char*) data) + m);
        for (size_t i=0; i<8; i++) 
        {
            if (i==4) printf(" "); // separate every four characters
            printf("%d", (my_char & bitmask) != 0);
            bitmask = bitmask >> 1;
        }
        printf("\n");
    }
} 

Then you can call this function for each element of your struct.

e.g.

typedef struct
{
    int a;
    char b;
    int c[20];
}my_struct_t;

my_struct_t mystruct;

..
printdata(mystruct.a,sizeof(int));
printdata(mystruct.b,sizeof(char));
printdata(mystruct.c, 20*sizeof(int));  

You can also pass the entire struct to the above function, but it will also print the padding bytes which is not what is needed.

Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31
0

This fit types what you want

#include <stdio.h>
#include <stdlib.h>
#define bitmask 0b1
void F1(void *a,int Len){
    int i,j;
    unsigned char*b=(unsigned char*)a;
    b+=Len-1;
    for(i=0;i<Len;i++,b--){
        for(j=7;j>-1;j--){
            printf("%d",((*b)&bitmask<<j)>>j);
        }
    }
    printf("\n");
}
int main(){ 

    unsigned int Q=10;
    F1(&Q,sizeof(unsigned int));

    unsigned short QQ=10;
    F1(&QQ,sizeof(unsigned short));

    unsigned char QQQ=10;
    F1(&QQQ,sizeof(unsigned char));
    return 0;
}
J CHEN
  • 494
  • 3
  • 9