1

I have a status register with 8 bits. I would like to move each individual bit to a byte for further processing. Seems like it should be easy but every solution I come up with is convoluted. I was thinking about iterating through the bits with a for next loop and dumping them into an array but my solution way too messy.

Matthew E. Miller
  • 557
  • 1
  • 5
  • 13
  • [What's the fastest way to pack 32 0/1 values into the bits of a single 32-bit variable?](https://stackoverflow.com/q/26200961/995714), [How to efficiently convert an 8-bit bitmap to array of 0/1 integers with x86 SIMD](https://stackoverflow.com/q/52098873/995714) – phuclv Aug 28 '19 at 02:39
  • It's not an answer to your question, but are you sure you need to do this ? I mean that you could very well use a bit mask every time you need to access a bit, instead of copying each bit in a different variable. Some thing like `if ( status_register & Mask_for_bit_i ) do_something();` will not be more complicated than `if (bits[i]) do_something();` – Guillaume Petitjean Aug 28 '19 at 08:17

3 Answers3

2

Here's basically what you're trying to do. It uses bitwise operators and a uint8_t array to make each bit an individual byte:

void bits_to_bytes(uint8_t status, uint8_t bits[8])
{
    int ctr;
    for( ctr = 0; ctr < 8; ctr++ )
    {
        bits[ctr] = (status >> ctr) & 1;
    }
}

OK, so a little more in-depth:

This code loops through the bits in a byte and then assigns bits[bit_number] to the bit_numberth bit of status.

If you want to reverse the order the bits are stored in, simply change bits[ctr] to bits[(8-1)-ctr].

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
1

For a start, you should be using uint8_t for eight-bit bit collections since char is fundamentally non-portable unless you add a lot of extra code for checking its size and signedness.

Something like this should suffice for your needs:

void BitsToBytes(uint8_t bits, uint8_t *bytes) {
    for (int i = 0; i < 8; ++i) {     // The type has exactly eight bits.
        *bytes++ = (bits > 127);      // 1 if high bit set, else 0.
        bits = (bits & 0x7f) << 1;    // Shift left to get next bit.
    }
}
:
// Call with:
uint8_t inputBits = 0x42;
uint8_t outputBytes[8];
BitsToBytes(inputBits, outputBytes);

This takes a type with eight bits and a buffer of eight bytes, then places the individual bits into each byte of the array:

              MSB  LSB
             +--------+
inputBits:   |abcdefgh|
             +--------+
             +---+---+---+---+---+---+---+---+
outputBytes: | a | b | c | d | e | f | g | h |
             +---+---+---+---+---+---+---+---+

If you want it to go the other way (where the LSB of the input is in element 0 of the array), you can simply change the body of the loop to:

*bytes++ = bits & 1; // 1 if low bit set, else 0.
bits = bits >> 1;    // Shift right to get next bit.
S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Isn't this a tad too complicated? – S.S. Anne Aug 28 '19 at 00:50
  • @JL2210: complicated in what way exactly? It does exactly what the question asks for and the calling of the function is relatively simple. – paxdiablo Aug 28 '19 at 00:51
  • But couldn't you just use bit-shifts and `& 1`, like in my solution? – S.S. Anne Aug 28 '19 at 00:52
  • It seems backwards to expectation, the least significant bit is conventionally numbered zero but this places it into `outputBytes[7]`. – caf Aug 28 '19 at 00:53
  • 1
    @JL2210: yes, but I prefer a function based solution so that it doesn't clutter up the code. I also have a natural need for the bytes to echo the bits in a left-to-right sense but that's probably more of a sytle thing :-) – paxdiablo Aug 28 '19 at 00:53
  • @caf My answer or paxdiablo's? – S.S. Anne Aug 28 '19 at 00:53
  • @JL2210: This one - yours puts bit 0 in `bits[0]` as I would expect. – caf Aug 28 '19 at 00:55
  • 1
    @caf, have added an addendum for that preference but I still prefer the current way :-) – paxdiablo Aug 28 '19 at 00:59
  • *you should be using `uint8_t` for eight-bit bit collections since `char` is fundamentally non-portable* Given [**7.20.1.1 Exact-width integer types**, paragraph 3](https://port70.net/~nsz/c/c11/n1570.html#7.20.1.1p3). I suspect there's not much *de facto* difference in portability between the two. The most portable would be `uint_least8_t`. – Andrew Henle Aug 28 '19 at 01:24
  • @Andrew, if uint8_t can be represented by an implementation, it must be. The problem with the `least` types is that you have to ensure nothing "leaks" into the bit positions above `b7`, lest checks like `> 127` will not work (in other words, you'll probably need to mask those bits to zero). If you don't *have* `uint8_t` then, yes, `least` is probably better (with a little extra work). Even `unsigned char` is workable with some more effort but I would totally steer clear of `char` just because of its signedness problems. – paxdiablo Aug 28 '19 at 01:48
0

You can use a double invocation of the ! operator to squash a zero/non-zero value to zero/one. Using this, the extracted value of bit n in status is !!(status & (1 << n)).

If you only have eight flags you might just create constants for the 8 values of 1 << n (0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80). This works particularly well if your flags all have individual names rather than numbers, so that you might have in a header file somewhere:

#define FLAG_FROB 0x01
#define FLAG_FOO  0x02
#define FLAG_BAR  0x04
#define FLAG_BAZ  0x08
#define FLAG_QUUX 0x10

Then in the code you'd just extract them as

flag_frob = !!(status & FLAG_FROB);
flag_foo = !!(status & FLAG_FOO);
flag_bar = !!(status & FLAG_BAR);
flag_baz = !!(status & FLAG_BAZ);
flag_quux = !!(status & FLAG_QUUX);
caf
  • 233,326
  • 40
  • 323
  • 462
  • Why would you need that when you could use `(status >> n) & 1`? It's simpler, and doesn't use unnecessary screaming. – S.S. Anne Aug 28 '19 at 00:59
  • 1
    @JL2210: Just because the shifted values here are constants rather than using a variable shift. Often you'll have those `(1 << n)` values as defined constants for the various flags anyway since they likely each have their own name. It all depends on whether you're dealing with 8 individually named independent flags or a set of analogous numbered flags (an example of the latter might be 8 free/busy flags for 8 numbered buffers). – caf Aug 28 '19 at 01:07
  • True, in fact, I use those myself. – S.S. Anne Aug 28 '19 at 01:15