Search code examples
c++unionsbit-fields

Valid use of bit-fields and unions


I wrote this code just for the fun of it:

union {
    struct {
        bool a : 1;
        bool b : 1;
        bool c : 1;
        bool d : 1;
        bool e : 1;
        bool f : 1;
        bool g : 1;
        bool h : 1;
    } a;
    uint8_t b;
} uni {0}; // sets .a bits to false

// union size  : 1 byte

I can toggle each bit individually:

uni.a.a = true;
uni.a.d = true;

cout << bitset<8>(uni.b) << endl; // Prints 000010001

And also use bit masks:

uni.b = 0b00001000;

if(uni.a.a) cout << "a";
if(uni.a.b) cout << "b";
if(uni.a.c) cout << "c";
if(uni.a.d) cout << "d";
if(uni.a.e) cout << "e";
if(uni.a.f) cout << "f";
if(uni.a.g) cout << "g";
if(uni.a.h) cout << "h";
// prints 'd'

I know there are other ways to do this (bitwise operations) but I like this design. My question is: is this a good use of bitfields and unions, in terms of reliability and performance?


Solution

  • My question is: is this a good use of bitfields and unions, in terms of reliability and performance?

    In terms of performance, what you are doing is probably as good as it is going to get, at least in terms of accessing memory at the bit level.

    In terms of reliability, it is probably OK across most modern systems. At the risk of sounding like a language lawyer, here are some areas where it could have different results across systems:

    1. sizeof(bool) isn't guaranteed to be 1, that is bool can be stored in memory larger than one byte. I don't know of any modern system where bool isn't the size of a byte, but you could imagine an older or bad implementation that makes bool to be the same size as an int. This would inherently throw off your union.
    2. Accessing a different member variable of a union can caused undefined behavior
    3. The byte order across systems can be different (e.g., big or little endian), leading to differences in which member of the union would represent the MSB.
    4. Technically the implementation can lay out the individual bits of a bit field in any order within a byte. Every implementation I know would order them in the order you defined it in the struct, but that doesn't have to happen.
    5. The implementation can insert padding between individual members of the struct such that individual bits are in different bytes of memory. Again, all implementations that I know of won't do this but it can happen.

    I don't think you would need to worry about the above. But, in terms of covering everything that could go wrong, I think the above list pretty well covers the really odd-ball scenarios that you could face if you really searched for an implementation that was a bit different.