Display the binary representation of a number in C? [duplicate]
Asked Answered
O

8

8

Possible Duplicate:
Is there a printf converter to print in binary format?

Still learning C and I was wondering:

Given a number, is it possible to do something like the following?

char a = 5;
printf("binary representation of a = %b",a);
> 101

Or would i have to write my own method to do the transformation to binary?

Outride answered 31/3, 2009 at 4:18 Comment(0)
P
14

Yes (write your own), something like the following complete function.

#include <stdio.h> /* only needed for the printf() in main(). */
#include <string.h>

/* Create a string of binary digits based on the input value.
   Input:
       val:  value to convert.
       buff: buffer to write to must be >= sz+1 chars.
       sz:   size of buffer.
   Returns address of string or NULL if not enough space provided.
*/
static char *binrep (unsigned int val, char *buff, int sz) {
    char *pbuff = buff;

    /* Must be able to store one character at least. */
    if (sz < 1) return NULL;

    /* Special case for zero to ensure some output. */
    if (val == 0) {
        *pbuff++ = '0';
        *pbuff = '\0';
        return buff;
    }

    /* Work from the end of the buffer back. */
    pbuff += sz;
    *pbuff-- = '\0';

    /* For each bit (going backwards) store character. */
    while (val != 0) {
        if (sz-- == 0) return NULL;
        *pbuff-- = ((val & 1) == 1) ? '1' : '0';

        /* Get next bit. */
        val >>= 1;
    }
    return pbuff+1;
}

Add this main to the end of it to see it in operation:

#define SZ 32
int main(int argc, char *argv[]) {
    int i;
    int n;
    char buff[SZ+1];

    /* Process all arguments, outputting their binary. */
    for (i = 1; i < argc; i++) {
        n = atoi (argv[i]);
        printf("[%3d] %9d -> %s (from '%s')\n", i, n,
            binrep(n,buff,SZ), argv[i]);
    }

    return 0;
}

Run it with "progname 0 7 12 52 123" to get:

[  1]         0 -> 0 (from '0')
[  2]         7 -> 111 (from '7')
[  3]        12 -> 1100 (from '12')
[  4]        52 -> 110100 (from '52')
[  5]       123 -> 1111011 (from '123')
Postmortem answered 31/3, 2009 at 4:44 Comment(6)
I see a buffer underflow if the binrep() function is not given enough space for the value it is printing. And, speaking from bitter (but long ago) experience, stuff writing off the front of an array can be really nasty to debug!Spirillum
Yes, that will be troublesome - if your ints are more than 32 bits, you have to make sure you increase SZ to suit.Postmortem
Fixed to prevent the buffer overflow.Postmortem
Quote: "buff: buffer to write to must be >= sz+1 chars." - sz is the size of the buffer, excluding the terminating null.Postmortem
@Pax: Oh, okay ... I'll delete my comment. I get queasy when exposed to a function taking a string size argument that is incompatible with a simple sizeof; requiring me to remember to add or subtract 1 is not cool, in my opinion.Josey
Well, it has precedent, in fgets(), so I guess it's not a total anti-pattern.Postmortem
T
29

There is no direct way (i.e. using printf or another standard library function) to print it. You will have to write your own function.

/* This code has an obvious bug and another non-obvious one :) */
void printbits(unsigned char v) {
   for (; v; v >>= 1) putchar('0' + (v & 1));
}

If you're using terminal, you can use control codes to print out bytes in natural order:

void printbits(unsigned char v) {
    printf("%*s", (int)ceil(log2(v)) + 1, ""); 
    for (; v; v >>= 1) printf("\x1b[2D%c",'0' + (v & 1));
}
Tattoo answered 31/3, 2009 at 4:21 Comment(16)
Nice bit hacks. Unreadable code FTW!Flycatcher
@Chris Lutz: Actually, this is as simple as they come :-)Tattoo
@Chris Lutz: I agree with dirkgently. The function is well named, and clearly written in a linear fashion. Each statement is simple and obvious.Unthread
Yeah, not sure I'd be inflicting this monstrosity :-) on someone "Still learning C". Still, it works.Postmortem
I upvoted, and actually do like the solution. I just am also a bit sarcastic sometimes. Sorry it seemed like I thought it was bad. I think it's quite readable, if you know bitwise operations. Which a lot of people unfortunately don't. (Also, the >>= and <<= operators just look a bit silly to me.)Flycatcher
@Pax: Do you equate terseness with monstrosity? Alas, any student of C has to live with such monstrosity, for that is the C way of life. The earlier they learn, the better it is.Tattoo
Obvious bug - it prints bits in reverse order. Non-obvious bug - it prints nothing for v = 0.Flycatcher
@Chris Lutz: +2; It was the other way round for me though :)Tattoo
Very confusing to show a string function in C that takes a buffer size as input, and doesn't use that size in a defensive (enough) manner. For sz == 0 && x == 0, it will still write "0" to the buffer.Josey
The other bug is that it only prints out for a byte at a time, not for 32-bit or 64-bit values. Though, since the question was about printing a 'char', maybe that doesn't matter.Spirillum
@Jonathan Leffler: This is by design. You may have already noted the input parameter.Tattoo
@unwind: Which buffer size parameter are you talking about?Tattoo
@dirk, I gather that buffer size comment was meant for my answer.Postmortem
@Pax: Oh, well, so I gathered :-) Just wanted a confirmation from unwind.Tattoo
I still don't understand this "for"Heuer
I will start adding that comment to some methods of mine that I know that I have not properly debugged. For myself it will be a reminder. For others, it will be a warning.Cardinale
F
27

Based on dirkgently's answer, but fixing his two bugs, and always printing a fixed number of digits:

void printbits(unsigned char v) {
  int i; // for C89 compatability
  for(i = 7; i >= 0; i--) putchar('0' + ((v >> i) & 1));
}
Flycatcher answered 31/3, 2009 at 6:1 Comment(6)
As icing on the cake you could also replace i = 7 with (sizeof(v)*8)-1Guacin
I'd do that if I could find a way to make the function take an argument of any type, rather than just an unsigned char. I tried using a void pointer, but I'm getting errors. I'll need to look into that more sometime though.Flycatcher
this worked for me:char* printbits(int v) { for(int i = (sizeof(v)*8)-1; i >= 0; i--) putchar('0' + ((v >> i) & 1)); }Larimore
Is there a way to have it return char*?Larimore
@David - Of course there is. Google around for other questions related to this. (Or ask your own, but I bet it's a duplicate.) You'll probably need to use malloc.Flycatcher
Also consider i = v ? (int)floor(log2(v)) : 0Thermophone
P
14

Yes (write your own), something like the following complete function.

#include <stdio.h> /* only needed for the printf() in main(). */
#include <string.h>

/* Create a string of binary digits based on the input value.
   Input:
       val:  value to convert.
       buff: buffer to write to must be >= sz+1 chars.
       sz:   size of buffer.
   Returns address of string or NULL if not enough space provided.
*/
static char *binrep (unsigned int val, char *buff, int sz) {
    char *pbuff = buff;

    /* Must be able to store one character at least. */
    if (sz < 1) return NULL;

    /* Special case for zero to ensure some output. */
    if (val == 0) {
        *pbuff++ = '0';
        *pbuff = '\0';
        return buff;
    }

    /* Work from the end of the buffer back. */
    pbuff += sz;
    *pbuff-- = '\0';

    /* For each bit (going backwards) store character. */
    while (val != 0) {
        if (sz-- == 0) return NULL;
        *pbuff-- = ((val & 1) == 1) ? '1' : '0';

        /* Get next bit. */
        val >>= 1;
    }
    return pbuff+1;
}

Add this main to the end of it to see it in operation:

#define SZ 32
int main(int argc, char *argv[]) {
    int i;
    int n;
    char buff[SZ+1];

    /* Process all arguments, outputting their binary. */
    for (i = 1; i < argc; i++) {
        n = atoi (argv[i]);
        printf("[%3d] %9d -> %s (from '%s')\n", i, n,
            binrep(n,buff,SZ), argv[i]);
    }

    return 0;
}

Run it with "progname 0 7 12 52 123" to get:

[  1]         0 -> 0 (from '0')
[  2]         7 -> 111 (from '7')
[  3]        12 -> 1100 (from '12')
[  4]        52 -> 110100 (from '52')
[  5]       123 -> 1111011 (from '123')
Postmortem answered 31/3, 2009 at 4:44 Comment(6)
I see a buffer underflow if the binrep() function is not given enough space for the value it is printing. And, speaking from bitter (but long ago) experience, stuff writing off the front of an array can be really nasty to debug!Spirillum
Yes, that will be troublesome - if your ints are more than 32 bits, you have to make sure you increase SZ to suit.Postmortem
Fixed to prevent the buffer overflow.Postmortem
Quote: "buff: buffer to write to must be >= sz+1 chars." - sz is the size of the buffer, excluding the terminating null.Postmortem
@Pax: Oh, okay ... I'll delete my comment. I get queasy when exposed to a function taking a string size argument that is incompatible with a simple sizeof; requiring me to remember to add or subtract 1 is not cool, in my opinion.Josey
Well, it has precedent, in fgets(), so I guess it's not a total anti-pattern.Postmortem
P
6
#include<iostream>
#include<conio.h>
#include<stdlib.h>
using namespace std;
void displayBinary(int n)
{
       char bistr[1000];
       itoa(n,bistr,2);       //2 means binary u can convert n upto base 36
       printf("%s",bistr);

}

int main()
{
    int n;
    cin>>n;
    displayBinary(n);
    getch();
    return 0;
}
Pulchritude answered 10/9, 2010 at 17:11 Comment(0)
S
4

Use a lookup table, like:

char *table[16] = {"0000", "0001", .... "1111"};

then print each nibble like this

printf("%s%s", table[a / 0x10], table[a % 0x10]);

Surely you can use just one table, but it will be marginally faster and too big.

Stairhead answered 31/3, 2009 at 4:52 Comment(0)
A
3

There is no direct format specifier for this in the C language. Although I wrote this quick python snippet to help you understand the process step by step to roll your own.

#!/usr/bin/python

dec = input("Enter a decimal number to convert: ")
base = 2
solution = ""

while dec >= base:
    solution = str(dec%base) + solution
    dec = dec/base
if dec > 0:
    solution = str(dec) + solution

print solution

Explained:

dec = input("Enter a decimal number to convert: ") - prompt the user for numerical input (there are multiple ways to do this in C via scanf for example)

base = 2 - specify our base is 2 (binary)

solution = "" - create an empty string in which we will concatenate our solution

while dec >= base: - while our number is bigger than the base entered

solution = str(dec%base) + solution - get the modulus of the number to the base, and add it to the beginning of our string (we must add numbers right to left using division and remainder method). the str() function converts the result of the operation to a string. You cannot concatenate integers with strings in python without a type conversion.

dec = dec/base - divide the decimal number by the base in preperation to take the next modulo

if dec > 0: solution = str(dec) + solution - if anything is left over, add it to the beginning (this will be 1, if anything)

print solution - print the final number

Agnomen answered 31/3, 2009 at 4:43 Comment(2)
You missed the case where the input is 0, which will print nothing in this case.Kirstinkirstyn
I don't think anyone would bother putting 0 into a converter as the answer is obvious, but choose your fix of choice. An if statement at the top of the script along with a sys.exit or check the value of the solution variable at the bottom.Agnomen
F
3

This code should handle your needs up to 64 bits.



char* pBinFill(long int x,char *so, char fillChar); // version with fill
char* pBin(long int x, char *so);                    // version without fill
#define width 64

char* pBin(long int x,char *so)
{
 char s[width+1];
 int    i=width;
 s[i--]=0x00;   // terminate string
 do
 { // fill in array from right to left
  s[i--]=(x & 1) ? '1':'0';  // determine bit
  x>>=1;  // shift right 1 bit
 } while( x > 0);
 i++;   // point to last valid character
 sprintf(so,"%s",s+i); // stick it in the temp string string
 return so;
}

char* pBinFill(long int x,char *so, char fillChar)
{ // fill in array from right to left
 char s[width+1];
 int    i=width;
 s[i--]=0x00;   // terminate string
 do
 {
  s[i--]=(x & 1) ? '1':'0';
  x>>=1;  // shift right 1 bit
 } while( x > 0);
 while(i>=0) s[i--]=fillChar;    // fill with fillChar 
 sprintf(so,"%s",s);
 return so;
}

void test()
{
 char so[width+1]; // working buffer for pBin
 long int   val=1;
 do
 {
   printf("%ld =\t\t%#lx =\t\t0b%s\n",val,val,pBinFill(val,so,0));
   val*=11; // generate test data
 } while (val < 100000000);
}

Output:
00000001 = 0x000001 =   0b00000000000000000000000000000001
00000011 = 0x00000b =   0b00000000000000000000000000001011
00000121 = 0x000079 =   0b00000000000000000000000001111001
00001331 = 0x000533 =   0b00000000000000000000010100110011
00014641 = 0x003931 =   0b00000000000000000011100100110001
00161051 = 0x02751b =   0b00000000000000100111010100011011
01771561 = 0x1b0829 =   0b00000000000110110000100000101001
19487171 = 0x12959c3 =  0b00000001001010010101100111000011
Faceoff answered 1/4, 2009 at 7:24 Comment(0)
E
2

You have to write your own transformation. Only decimal, hex and octal numbers are supported with format specifiers.

Emmanuelemmeline answered 31/3, 2009 at 4:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.