4

In my opinion, one bit is all you ever need for a binary variable like bool. Is it in any way a bad decision to explicitly tell all bools to use only 1 bit?

struct Banana { 

    // little fields
    bool on_off : 1;
    bool yes_no : 1;
    bool left_right : 1;
    bool alive_dead : 1;
    bool in_out : 1;

};

Edit:

I know that it is not possible to take the address of a field. Any other downsides?

Oleksiy
  • 37,477
  • 22
  • 74
  • 122

3 Answers3

6

If you have LOTS of these things, it saves space. But it does add at least an extra AND or OR instruction for each clear/set/check operation over the normal one-byte solution.

In the whole scheme of things, unless you actually have a HUGE number, there is probably no benefit.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • In other words, it is a typical time/space trade off. (Except that modern memory access can change the terms of the trade off. If you're dealing with large vectors of the type, the reduced memory use can improve locality, to the point of making the bit field solution more efficient in run-time as well. But you won't know until you measure. – James Kanze Aug 15 '13 at 09:33
  • It requires an extra `AND` or `OR` and a `left shift`. – gifnoc-gkp Aug 15 '13 at 09:34
  • @TheOtherGuy Not necessarily. It depends on how it is used. The most common use of a `bool` is in a conditional, in which case, no shifting is needed. (Also, this depends on the implementation. There are, or at least have been processors which allow addressing a single bit. The VAX, for example.) – James Kanze Aug 15 '13 at 09:37
  • The left shift can almost always be eliminated, unless you are converting to standalone `bool` value [well, it can then too, if it's replaced with a conditional set instruction]. (Actually, x86 has a specific instructions for `bit test` in a large set of bits, but it's not as easy to use as a single and). – Mats Petersson Aug 15 '13 at 09:41
  • @MatsPetersson To use multiple bools without wasting 7 bits for each, 'd make a char and fit 8 of them into it. That's why I said it will probably require a left shift too. – gifnoc-gkp Aug 15 '13 at 09:45
  • Right, but if the compiler knows what you are doing (e.g. using a bitfield in a struct), the code can be optimised to test bit X with a single and with the value `(1 << X)`. Storing a bit is or with that same value, and clearing a bit is and with the inverse (`~(1 << X)`) – Mats Petersson Aug 15 '13 at 09:50
  • 1
    As a reference point, Clang uses this in its AST classes. An order of magnitude is that it takes from a couple hundred thousands to several millions of instances to compile a single source file (because of inclusion...). It's obviously hardly typical to have *so many* instances. – Matthieu M. Aug 15 '13 at 10:52
3

There's a time/space/synchronisation trade off.

Clearly you can store 32 times as many bits in the same space.

However, to access an individual bool you need at least a masking operation, and probably a shift (though under certain circumstances, that is likely to be optimised out).

This has consequences if multiple threads of control attempt to modify booleans as you've changed a simple write for your update to a read/modify/write so now you have to add synchronisation.

Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
  • Good point about synchronization. With this approach you can't share just one Boolean value between threads: you have to share the entire stored value with all the Booleans. So touching **any** of the Boolean values means updating every cache that holds the entire stored value, even if that thread has no interest in the Boolean that was actually modified. – Pete Becker Aug 15 '13 at 11:51
2

I have encountered a couple of good compilers/architectures/functions where moving booleans into bitfields has drastically improved code quality and performance.

Unfortunately GCC is not one of those compilers (or was not last time I tested this).

When things go right, storing several booleans in a single register can relieve a lot of register pressure, consequently eliminating a lot of register spill to the stack and making the rest of the code much more efficient.

If the architecture has an adequate set of bit handling instructions then the test and manipulation operations can be as compact or more compact than comparable operations to extract booleans from whole registers or, worse, the stack.

Generally (even on x86), bit-packing booleans should result in more efficient code, but the limitation is the compiler.

sh1
  • 4,324
  • 17
  • 30