15

I am trying to write a program in C that prints bits of int. for some reason i get wrong values,

void printBits(unsigned int num){
    unsigned int size = sizeof(unsigned int);
    unsigned int maxPow = 1<<(size*8-1);
    printf("MAX POW : %u\n",maxPow);
    int i=0,j;
    for(;i<size;++i){
        for(j=0;j<8;++j){
            // print last bit and shift left.
            printf("%u ",num&maxPow);
            num = num<<1;
        }
    }
}

My question, first why am i getting this result (for printBits(3)).

MAX POW : 2147483648 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 2147483648 214748364 8

second is there a better way to do this ?

blahdiblah
  • 33,069
  • 21
  • 98
  • 152
sam ray
  • 257
  • 1
  • 4
  • 11
  • Is this what you want? http://stackoverflow.com/questions/1024389/print-an-int-in-binary-representation-using-c – David Feb 14 '12 at 16:43
  • Is that really the output, or is the formatting broken? It doesn't match the print statements ... Oh, and you don't say what value you're passing in for `num`, either – Useless Feb 14 '12 at 16:44
  • @Useless fixed question, output is for printBits(3). – sam ray Feb 14 '12 at 16:52

7 Answers7

25

You are calculating the result correctly, but you are not printing it right. Also you do not need a second loop:

for(;i<size*8;++i){
    // print last bit and shift left.
    printf("%u ",num&maxPow ? 1 : 0);
    num = num<<1;
}

If you'd like to show off, you could replace the conditional with two exclamation points:

printf("%u ", !!(num&maxPow));
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
10

To address point two, I'd consider the following, which is simplified a bit for ease of understanding.

void printBits(unsigned int num)
{
   for(int bit=0;bit<(sizeof(unsigned int) * 8); bit++)
   {
      printf("%i ", num & 0x01);
      num = num >> 1;
   }
}
Adam Davis
  • 91,931
  • 60
  • 264
  • 330
  • 2
    I'm still struggling to understand endianess, but am I right thinking that this prints bits in "big endian", as opposed to "little endian" which is more common? E.g. `1 0 0 0 0 0 0` for the number `1` in 8-bits, as opposed to `0 0 0 0 0 0 0 1` for the same number in little endian. – Marcus Ottosson Jan 13 '16 at 15:12
  • 1
    The value 1 in 16 bits it will either be 00000000 00000001 or 00000001 00000000 depending on Endianess. It is not mirrored like in your example. – Ray Hulha Sep 23 '16 at 13:33
  • It prints the values vice versed. – Osama F Elias Mar 08 '22 at 15:34
9

The result you get is because num&maxPow is either 0 or maxPow. To print 1 instead of maxPow, you could use printf("%u ", num&maxPow ? 1 : 0);. An alternative way to print the bits is

while(maxPow){
    printf("%u ", num&maxPow ? 1 : 0);
    maxPow >>= 1;
}

i.e. shifting the bitmask right instead of num left. The loop ends when the set bit of the mask gets shifted out.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
3

How about this Macro:

#define print_bits(x)                                            \
  do {                                                           \
    unsigned long long a__ = (x);                                \
    size_t bits__ = sizeof(x) * 8;                               \
    printf(#x ": ");                                             \
    while (bits__--) putchar(a__ &(1ULL << bits__) ? '1' : '0'); \
    putchar('\n');                                               \
  } while (0)

char c = 3;
int i = -1;
print_bits(c);
print_bits(i);

output:

c: 00000011
i: 11111111111111111111111111111111

This Marco can be used on any primitive datatype and the expression 'x' will be evaluated only once. So you should be safe from side effects.

With the typeof construct you could extend this to structures too:

#define print_bits(x)                                             \
  do {                                                            \
    typeof(x) a__ = (x);                                          \
    char *p__ = (char *)&a__ + sizeof(x) - 1;                     \
    size_t bytes__ = sizeof(x);                                   \
    printf(#x ": ");                                              \
    while (bytes__--) {                                           \
      char bits__ = 8;                                            \
      while (bits__--) putchar(*p__ & (1 << bits__) ? '1' : '0'); \
      p__--;                                                      \
    }                                                             \
    putchar('\n');                                                \
  } while (0)

print_bits((struct in_addr){.s_addr = 0xff00ff00});

output:

(struct in_addr){.s_addr = 0xff00ff00}: 11111111000000001111111100000000

Could be useful e.g. in print debugging.

(typeof is a GNU-extension, use __typeof__ instead if it must work in ISO C programs)

breiters
  • 116
  • 6
  • This isn't portable, and using double-underscores before an identifier name is undefined behavior. – S.S. Anne Feb 26 '20 at 16:22
  • Might be off topic but do you know what's the 'standard' way to avoid confusion with identifiers within a macro and why this isn't portable? Thx – breiters Feb 26 '20 at 20:08
  • I usually suffix (rather than prefix) with an underscore or two. `typeof` is a GNU C extension. You can use `unsigned long long` and take the size of `x` instead of `a`. (also, a single underscore prefix is reserved for file scope so you could probably use that, too) – S.S. Anne Feb 26 '20 at 20:52
0
void print_bits(unsigned int x)
{
    int i;
    for(i=8*sizeof(x)-1; i>=0; i--) {
        (x & (1 << i)) ? putchar('1') : putchar('0');
    }
    printf("\n");
}
Nikhil Vidhani
  • 709
  • 5
  • 11
0

I guess You can remove some code and

void printB(unsigned int num){
    unsigned int size = sizeof(unsigned int);
    int i;
    for(i = size*8-1; i>= 0; i--){
        printf("%u",(num >>i) & 1 );
    }
    printf("\n");
}
LittleEaster
  • 527
  • 7
  • 10
0
// example code `ch7-8.c` from the book `明解C言語 3nd` of Shibata Bouyou

#include<stdio.h>

int count_bits(unsigned x)
{
    int bits = 0;
    while (x) {
        if (x & 1U) bits++;
        x >>= 1;
    }
    return bits;
}

int int_bits(void)
{
    return count_bits(~0U);
}

void print_nbits(unsigned x, unsigned n)
{
    int i = int_bits();
    i = (n < i) ? n - 1 : i - 1;
    for (; i >= 0; i--)
        putchar(((x >> i) & 1U) ? '1' : '0');
}

int main(void)
{
    unsigned i;

    for (i = 0; i <= 65535U; i++) {
        printf("%5u ", i);
        print_nbits(i, 16);
        printf(" %06o %04X\n", i, i);
    }

    return 0;
}

output:

    0 0000000000000000 000000 0000
    1 0000000000000001 000001 0001
    2 0000000000000010 000002 0002
    3 0000000000000011 000003 0003
    4 0000000000000100 000004 0004
    5 0000000000000101 000005 0005
    6 0000000000000110 000006 0006
    7 0000000000000111 000007 0007
    8 0000000000001000 000010 0008
    9 0000000000001001 000011 0009
   10 0000000000001010 000012 000A
   11 0000000000001011 000013 000B
   12 0000000000001100 000014 000C
   13 0000000000001101 000015 000D
   14 0000000000001110 000016 000E
   15 0000000000001111 000017 000F
   16 0000000000010000 000020 0010
micfan
  • 800
  • 8
  • 12