Look at the program printbits.c:
print_bits(unsigned char c) { .... } main() { unsigned char c; int i; while (1) { printf("Enter an integer between 0 and 255: "); fflush(stdout); if (scanf("%d", &i) != 1) exit(0); if (i < 0 || i > 255) { printf("Bad value of i\n"); } else { c = (unsigned char) i; print_bits(c); putchar('\n'); } } }This repeatedly takes an integer between 0 and 255, puts it into an unsigned char (i.e. one byte), and then calls print_bits() on it. Print_bits() prints out the bits. Don't worry about how it is implemented yet. The output should be straightforward -- the bits look as you think they should:
UNIX> printbits Enter an integer between 0 and 255: 0 00000000 Enter an integer between 0 and 255: 1 00000001 Enter an integer between 0 and 255: 2 00000010 Enter an integer between 0 and 255: 3 00000011 Enter an integer between 0 and 255: 4 00000100 Enter an integer between 0 and 255: 5 00000101 Enter an integer between 0 and 255: 255 11111111 Enter an integer between 0 and 255: 254 11111110 Enter an integer between 0 and 255: < CNTL-D > UNIX>
UNIX> and Enter two integers between 0 and 255: 1 0 00000001 & 00000000 = 00000000 Enter two integers between 0 and 255: 1 1 00000001 & 00000001 = 00000001 Enter two integers between 0 and 255: 1 2 00000001 & 00000010 = 00000000 Enter two integers between 0 and 255: 1 3 00000001 & 00000011 = 00000001 Enter two integers between 0 and 255: 2 3 00000010 & 00000011 = 00000010 Enter two integers between 0 and 255: 0 40 00000000 & 00101000 = 00000000 Enter two integers between 0 and 255: 255 40 11111111 & 00101000 = 00101000 Enter two integers between 0 and 255: 0 89 00000000 & 01011001 = 00000000 Enter two integers between 0 and 255: 255 89 11111111 & 01011001 = 01011001 Enter two integers between 0 and 255: < CNTL-D > UNIX>If a number is all zeros except for a one in the i-th position (this means that the number is 2^(i-1)) then that number bitwise-and x is equal to zero or that number, depending on whether x has a bit set in the i-th position. Therefore (4 & 7) equals 4 since 7 has its bit in the third position set.
Similarly, if you are interested in what the lowest i bits of a byte are, you can take that byte bitwise-and (2^i)-1. For example, if you want to see what the lowest three bits are of a byte, you take that byte bitwise-and (2^3)-1 = 7. For example, the lowest three bits of 89 are (89&7)=1:
UNIX> and Enter two integers between 0 and 255: 4 7 00000100 & 00000111 = 00000100 Enter two integers between 0 and 255: 4 2 00000100 & 00000010 = 00000000 Enter two integers between 0 and 255: 89 7 01011001 & 00000111 = 00000001 Enter two integers between 0 and 255: 91 7 01011011 & 00000111 = 00000011 Enter two integers between 0 and 255: < CNTL-D > UNIX>
UNIX> or Enter two integers between 0 and 255: 0 1 00000000 | 00000001 = 00000001 Enter two integers between 0 and 255: 1 2 00000001 | 00000010 = 00000011 Enter two integers between 0 and 255: 1 3 00000001 | 00000011 = 00000011 Enter two integers between 0 and 255: 0 40 00000000 | 00101000 = 00101000 Enter two integers between 0 and 255: 255 40 11111111 | 00101000 = 11111111 Enter two integers between 0 and 255: 0 89 00000000 | 01011001 = 01011001 Enter two integers between 0 and 255: 255 89 11111111 | 01011001 = 11111111 Enter two integers between 0 and 255: < CNTL-D > UNIX>
UNIX> exor Enter two integers between 0 and 255: 1 2 00000001 ^ 00000010 = 00000011 Enter two integers between 0 and 255: 1 3 00000001 ^ 00000011 = 00000010 Enter two integers between 0 and 255: 255 0 11111111 ^ 00000000 = 11111111 Enter two integers between 0 and 255: 255 255 11111111 ^ 11111111 = 00000000 Enter two integers between 0 and 255: 1 1 00000001 ^ 00000001 = 00000000 Enter two integers between 0 and 255: < CNTL-D > UNIX> complement Enter an integer between 0 and 255: 0 ~ 00000000 = 11111111 Enter an integer between 0 and 255: 1 ~ 00000001 = 11111110 Enter an integer between 0 and 255: 40 ~ 00101000 = 11010111 Enter an integer between 0 and 255: 255 ~ 11111111 = 00000000 Enter an integer between 0 and 255: < CNTL-D > UNIX>
UNIX> leftshift Enter an integer and a shift amount: 1 0 00000001 << 0 = 00000001 Enter an integer and a shift amount: 1 1 00000001 << 1 = 00000010 Enter an integer and a shift amount: 1 2 00000001 << 2 = 00000100 Enter an integer and a shift amount: 1 3 00000001 << 3 = 00001000 Enter an integer and a shift amount: 1 4 00000001 << 4 = 00010000 Enter an integer and a shift amount: 3 1 00000011 << 1 = 00000110 Enter an integer and a shift amount: 3 0 00000011 << 0 = 00000011 Enter an integer and a shift amount: 0 1 00000000 << 1 = 00000000 Enter an integer and a shift amount: 3 8 00000011 << 8 = 00000000 Enter an integer and a shift amount: < CNTL-D > UNIX> rightshift Enter an integer and a shift amount: 1 0 00000001 >> 0 = 00000001 Enter an integer and a shift amount: 1 1 00000001 >> 1 = 00000000 Enter an integer and a shift amount: 8 1 00001000 >> 1 = 00000100 Enter an integer and a shift amount: 8 2 00001000 >> 2 = 00000010 Enter an integer and a shift amount: 8 3 00001000 >> 3 = 00000001 Enter an integer and a shift amount: 255 1 11111111 >> 1 = 01111111 Enter an integer and a shift amount: 255 7 11111111 >> 7 = 00000001 Enter an integer and a shift amount: < CNTL-D > UNIX>You'll note, left shifting by 1 multiplies by 2, and right shifting by one divides by two. In general, left shifting by i multiplies by 2^i, and right shifting by i divides by 2^i.
However, a word of caution. Yes, left-shifting by one multiplies by 2 faster than doing x*2. However, do not do this if you want to multiply by two unless your code really has to be optimally fast, or unless it's pretty clear what you're doing. Otherwise, your code becomes extremely hard to read.
Now that you know all this, implementing print_bits() is pretty simple:
print_bits(unsigned char c) { unsigned int i; for (i = 1 << 7; i != 0; i >>= 1) { if (i&c) putchar('1'); else putchar('0'); } }Yes, I could have done:
for (i = 1 << 7; i != 0; i >>= 1) { putchar('0'+((i&c)>0)); }or some such garbage, but again, make your code readable. A good compiler can probably make your readable code as fast as unreadable code.