Combining Enum Value using Bitmask

48,405

Solution 1

I am going to assume that myState has the type of your enum State.

The traditional use of enum is to create the constant values that a variable of this type can take. You wish to set you variable myState to a combination of the values defined in the enum.

The enum defines 1, 2, 4, and 8 as valid values, yet you want to be able to set the variable to 4 | 2 = 6. While C uses your implementation-defined int type for all enum, it is not the case in C++. myState = 6 is not valid in C++. Actually, myState = 4 is not either valid in C++, you need to cast explicitly or use one of the constant names of the enum.

Although possible in C, it is not good practice to set myState to a value that is not defined by its type (for example to 6).

In your case, a solution that seems consequent would be:

typedef enum {
    OTHER,
    MINIMIZED,
    MAXIMIZED
} win_size_t;

typedef struct {
    win_size_t current;
    win_size_t next;
} state_t;

state_t myState;

That way, you can write to the fields current and next undependently.

If you still want to have bit fields, you can set the size of the elements of your struct in bits. It is kind of dangerous though, the implementation of bit fields depend on your compiler. I am not even sure if compilers would accept to have an enum type in a bit field (should be ok in C, since enums are int).

typedef struct {
    win_size_t current : 2;  // not tested
    win_size_t next : 2;
} state_t;

The previous given solutions are valid of course. My point is that if your variable myState has your enum State as type, it should only use the members of the enum for its values, not a combination.

Maybe myState has another type, what do I know.


If myState is not of the enum State type, then you may use the constants defined in your enum in combination.

enum State {
    MINIMIZING = (1u << 0),
    MAXIMIZING = (1u << 1),
    MINIMIZED  = (1u << 2),
    MAXIMIZED  = (1u << 3),
};

unsigned int myState = 0;

myState |= MAXIMIZED;  // sets that bit
myState &= ~MAXIMIZED; // resets that bit

This allows you to do two things in one assignment:

myState = MAXIMIZED | MINIMIZING;

But also things you are not likely to want:

myState = MAXIMIZED | MINIMIZED;  // does that make sense?

Solution 2

Use a different bit for every value in your enumeration, such as:

enum State 
{
  minimizing = 0x01, // 00000001
  maximizing = 0x02, // 00000010
  minimized  = 0x04, // 00000100
  maximized  = 0x08  // 00001000
}:

Then, you can combine multiple values with bitwise or (minimizing | maximized) and test for values with bitwise and (bool is_minimized = (flags & minimized);).

Solution 3

I just tried this in VS2012, the optimizer seems to correctly combine bits without any need for assistance if you're using bitfields.

struct BITS { int x: 1; int y:1; };

then

BITS b;
b.x = b.y = 1;

Sets both bits with one instruction.

Solution 4

You can get this effect by specifying all fields in the enum and increased in powers of two to get the bitmask effect. For example, in your case:

enum State
{
    minimizing = 1,
    maximizing = 2,

    minimized = 4,
    maximized = 8
};

So you can then have your combinations of (State.maximized | State.minimizing). However this won't apply the restriction of only being State.maximized or State.minimized. If you want to do that you could convert them to a single bit, but I imagine in this example you would want to be able to have a case where it is neither maximized nor minimized.

Share:
48,405
Thomas Joulin
Author by

Thomas Joulin

I'm an iOS/Windows Phone developer

Updated on July 09, 2022

Comments

  • Thomas Joulin
    Thomas Joulin almost 2 years

    I understand it's possible to use bitmasks in enum values, but I don't know how to create it.

    I have a simple enum :

    enum State
    {
        minimizing = 0,
        maximizing,
    
        minimized,
        maximized
    };
    

    A state is always State.minimized or State.maximized, and can have additional state on resize. So something can be Maximized and minimizing

  • justin
    justin over 13 years
    which is usually written using shifts
  • Thomas Joulin
    Thomas Joulin over 13 years
    but then, how can I use it ? Like i have : myState = minimized; if (isMaximizing) { myState = maximizing } I want to set the maximizing state, without loosing the minimized state
  • Gauthier
    Gauthier over 13 years
    Then you can use myState |= maximizing;. This sets the bit you're interesting in without touching the other bits. For zeroing, use myState &= ~maximizing;. Be careful when doing comparisons, myState == minimized won't work, you'd need (myState & minimized) == minimized (or != 0). If I were you, I'd consider a struct with one field as "current state" and another for "next state".
  • Gauthier
    Gauthier over 13 years
    Question of taste, but I prefer: (1u << 0), (1u << 1), (1u << 2), (1u << 3). It is more clear which bit you mean.
  • Gauthier
    Gauthier over 13 years
    Note that while the enum State defines some constants, it does not define a combination of them. If myState is minimized and maximizing, the resulting value is 0x02 | 0x04, that is 0x06. Not a value defined by your enum.
  • Thomas Joulin
    Thomas Joulin over 13 years
    thanks ! I went for option #1. Indeed that makes no sens that MAXIMIZED | MINIMIZED is possible, and for it's better for readability to have two enums.
  • Natan Yellin
    Natan Yellin almost 13 years
    Why define the values in hex notation? minimizing = 1 works too
  • Gauthier
    Gauthier about 11 years
    @NatanYellin: it does, but if you are to add one more state and you are using decimal, you'd have to write 16. Say that you the want to set two bits, bit 4 and bit 1. The result is 18 in decimal, which is less readable than 0x12 (if this is not obvious, try to identify what bits are set in 2398 decimal. Much easier if you have the equivalent 0x95E). If you are interested in which bits are set, hexadecimal is the way to go.
  • Dávid Tóth
    Dávid Tóth almost 7 years
    Please note, that restricting enumerations to bit-fileds are undefined behavior and the result depends on the compiler. Also please correct me If I'm wrong.
  • Gauthier
    Gauthier almost 7 years
    @DavidTóth You seem to be correct, thanks for this! stackoverflow.com/a/33590935/108802