9

Right now, what I do is this:

void print_bits(unsigned int x)
{
    int i;
    for(i=WORD_SIZE-1; i>=0; i--) {
        (x & (1 << i)) ? putchar('1') : putchar('0');
    }
    printf("\n");
}

Also, it would be great to have a solution independent of word size (currently set to 32 in my example).

T.C.
  • 133,968
  • 17
  • 288
  • 421
Nikhil Vidhani
  • 709
  • 5
  • 11
  • 3
    `sizeof(x) * CHAR_BIT` – T.C. Sep 07 '14 at 10:16
  • 1
    Sidenote, `1 << i` for `i = WORDSIZE-1` is suspicious. – harold Sep 07 '14 at 10:22
  • 4
    For small types, you *could* consider a lookup table. This doesn't scale to larger types. – Oliver Charlesworth Sep 07 '14 at 10:24
  • 8
    Can I ask a question? **Why** you have to do it without a loop? Is it just for testing or...something else? – Adriano Repetti Sep 07 '14 at 10:31
  • 2
    it would also be possible to create a recursive function to avoid the loop, but it has no advantages. – wimh Sep 07 '14 at 10:33
  • 6
    What specifically are you hoping to achieve by eliminating the loop? – NPE Sep 07 '14 at 10:43
  • I just want the operation to be as fast as possible; so was exploring the solution without using a loop. @harold why do you seem suspicious about it ? – Nikhil Vidhani Sep 07 '14 at 10:50
  • If the integral types you're converting are assuredly a power of two in byte-size, [you may find this mildly amusing](http://ideone.com/6wAC9M). – WhozCraig Sep 07 '14 at 11:12
  • @ACreator even if your suggestion would work, would it be faster than bit shifting? – macfij Sep 07 '14 at 11:16
  • 17
    Premature optimization. "Printing" and "as fast as possible" are almost never used in the same sentence ;-) The *massive* overhead of `printf` (or `puts` or `putchar`) is magnitudes larger than the gain of any loop unrolling. Storing the characters in a buffer, then only printing once already should be better. – Jongware Sep 07 '14 at 11:25
  • 1
    As Jongware said you're worrying about performance but: 1) writing output somewhere is many times slower than your loop (even in one shot printing), you won't ever notice any measurable gain (and even if you can measure it...your users won't see it). – Adriano Repetti Sep 07 '14 at 22:13
  • the intent is to access all the bits w/o using a loop. Printing them is just one of the use case. I may well want to convert a 32bit integer number into a 32-byte character string of '1's and '0's. – Nikhil Vidhani Sep 11 '14 at 12:50

4 Answers4

3

How about this:

void print2Bits(int a) {
    char* table[] = {
        "00",
        "01",
        "10",
        "11"
    };
    puts(table[a & 3]);
}

void printByte(int a) {
    print2Bits(a >> 6);
    print2Bits(a >> 4);
    print2Bits(a >> 2);
    print2Bits(a);
}

void print32Bits(int a) {
    printByte(a >> 24);
    printByte(a >> 16);
    printByte(a >> 8);
    printByte(a);
}

I think, that's the closes you'll get to writing a binary number without a loop.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • 1. That is still more or less a loop (with 4 iterations instead of 32). 2. The size of `int` is not necessarily 32 bits on all platforms (i.e., it is not dictated by the C-language standard). So you should use `sizeof(int)` along with `CHAR_BIT` (defined in file `limits.h`). Applying these fixes will eventually force you to use a loop. – barak manos Sep 07 '14 at 11:38
  • @barakmanos Point 2 is precisely the reason why I called the last function `print32Bits()` and not `printInt()`. It is true, without a loop, you are not flexible enough to accomodate for different integer sizes. And, yes, it's pretty much an unrolled loop. But the hierarchical decomposition reduces the amount of code quite nicely. – cmaster - reinstate monica Sep 07 '14 at 12:14
  • There's actually a lot more code here than in a simple `for` loop. – barak manos Sep 07 '14 at 12:16
  • 2
    @barakmanos Which is, why I would never write it myself. But the OP asked for it :-) – cmaster - reinstate monica Sep 07 '14 at 12:20
  • 1
    BTW, mathematically, the best table-entry size should be `log(32)`, i.e., 5 characters per string. It would probably make the implementation much harder though, but 4 characters per string might be both optimized and relatively easy to implement. – barak manos Sep 07 '14 at 12:43
2

You may try itoa. Although it is not in standard C lib, it is available in most C compilers.

void print_bits(int x)
{
    char bits[33];
    itoa(x, bits, 2);
    puts(bits);
}
ACcreator
  • 1,362
  • 1
  • 12
  • 29
  • `#include ` and change `33` to `sizeof(x)*CHAR_BIT+1`. BTW, `itoa` most likely still performs the loop that OP is hoping to avoid... – barak manos Sep 07 '14 at 11:50
  • 3
    Also consider that itoa is not ANSI-C nor C++. – Jens Wirth Sep 07 '14 at 11:53
  • @ACcreator couldn't find itoa ? Where (header file) is it declared ? – Nikhil Vidhani Sep 11 '14 at 12:52
  • @NikhilVidhani Try including `stdlib.h`. You may refer to http://en.wikibooks.org/wiki/C_Programming/C_Reference/stdlib.h/itoa . As I have mentioned in the answer, it is a widespread **non-standard** extension, so it is possible that `itoa` is not available in your compiler. – ACcreator Sep 11 '14 at 13:30
2

Rather than making multiple calls to putchar or printf in a loop it's likely to be more efficient to build a temporary string first and then output that via one call to e.g. puts:

void print_bits(unsigned int x)
{
    const unsigned int n = sizeof(x) * CHAR_BIT;
    unsigned int mask = 1 << (n - 1);
    char s[n + 1];

    for (unsigned int i = 0; i < n; ++i)
    {
        s[i] = (x & mask) ? '1' : '0';
        mask >>= 1;
    }
    s[n] = '\0';
    puts(s);
}

LIVE DEMO

Paul R
  • 208,748
  • 37
  • 389
  • 560
1

Here is a little hacky way of doing it for byte I found some time ago. I think it's worth linking here despite it not being the best solution. http://gynvael.coldwind.pl/n/c_cpp_number_to_binary_string_01011010

void to_bin(unsigned char c, char *out) {
    *(unsigned long long*)out = 0x3030303030303030ULL // ASCII '0'*8
        + (((c * 0x8040201008040201ULL)   // spread out eight copies of c
           >>7) & 0x101010101010101ULL);  // shift to LSB & mask
}

Method provided by @cmaster is optimal and clean. Doing it in parts of 8 bits could be better though. You would construct the table in a loop using your method to avoid writing 256 strings manually. I don't think memory would be an issue too (it would take about 2kB).

Although I don't think there is a way to do it for variable of any size without loop.

greybeard
  • 2,249
  • 8
  • 30
  • 66
Sopel
  • 1,179
  • 1
  • 10
  • 15