Search code examples
c++c++11enumsbitwise-operators

Why bitwise OR and AND logic is not working as expected?


I have the below sample code. I was always under the impression that doing Bitwise OR on enum values, will allow me to check the result (using Bitwise AND) to see which enum values are included in the result and which are not.

For example, if I do result = mouse | headphone, then I can check agaist result & mouse == mouse as condition to know if mouse is included in result or not. But it seem that whatever I & result with, say X, I always end up with X. Why?

In the below code, I thought that the if should fail since straw was not included in options, but it does not..

#include <iostream>
#include <iomanip>

using namespace std;

enum Stock  
{
    milk,
    choclate,
    tv,
    cable,
    mouse,
    fan,
    headphone,
    cup,
    straw,
    pen,
    candy,
    glasses,
    book,
    plug

};


int main()
{
    Stock options = static_cast<Stock>( static_cast<int>(mouse) | static_cast<int>(headphone)
                                            | static_cast<int>(cup) | static_cast<int>(pen)     );

    if ((static_cast<int>(loptions)) & (static_cast<int>(straw)) == static_cast<int>(straw))
    {
        cout << "bring straw!" << endl;
    }

    system("PAUSE");
    return 0;
}

Edit:

Even when I add unique-bit set for the enum values, it does not work. For the below code, it ignores both if() statements when I am expecting it to display "bring cup" instead:

enum Stock
{
    milk = 1,
    choclate = 2,
    tv = 4,
    cable = 8,
    mouse = 16,
    fan = 32,
    headphone = 64,
    cup = 128,
    straw = 256,
    pen = 512,
    candy = 1024,
    glasses = 2048,
    book = 4096,
    plug = 8192

};


int main()
{
    Stock options = static_cast<Stock>(static_cast<int>(mouse) | static_cast<int>(headphone)
                                        | static_cast<int>(cup) | static_cast<int>(pen));

    if ((static_cast<int>(options)) & (static_cast<int>(straw)) == static_cast<int>(straw))
    {
        cout << "bring straw!" << endl;
    }

    if ((static_cast<int>(options)) & (static_cast<int>(cup)) == static_cast<int>(cup))
    {
        cout << "bring cup!" << endl;
    }

    system("PAUSE");
    return 0;
}

Solution

  • To use enums as bitsets (or flags) you need to make sure the binary representation for each enum value contains exactly one bit set to 1. In other words, each enum value needs to be a power of two. Example :

    enum Stock  
    {
        milk = 1,     // 0b0001
        choclate = 2, // 0b0010
        tv = 4,       // 0b0100
        cable = 8     // 0b1000
        // etc.
    };
    

    Otherwise, bit-wise logical operators won't be able to differentiate between certain values and certain combinations of other values. In the original code chocolate, tv and cable have the values 1, 2 and 3 respectively. In binary, that is 01, 10 and 11. ORing chocolate and tv produces 11 (0b01 | 0b10 == 0b11) which is the same value as cable. The combination of the chocolate and tv is not distinguishable from the cable flag.

    But c++ provides std::bitset. This class allows you to easily manipulate a bit set in a way similar to an array of bits. You can then just use your original enum and use each enum value as the index of a bit.