Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Assigning Enums explicit values using bit shifting

I have been looking at some code from open source projects and noticed that on more than one occassion the values of enums were being assigned through bitshifting a value an incremental number of places. I cannot see any specific reason for doing this, nor can I see an improvement in efficientcy over assigning the values by just incrementing +1.

Regardless this probably makes little sense without some code to demonstrate what has confused me.

Class 1

enum EventType {
        NONE                = 0,
        PUSH                = 1<<0,
        RELEASE             = 1<<1,
        DOUBLECLICK         = 1<<2,
        DRAG                = 1<<3,
        MOVE                = 1<<4,
        KEYDOWN             = 1<<5,
        KEYUP               = 1<<6,
        FRAME               = 1<<7,
        RESIZE              = 1<<8,
        SCROLL              = 1<<9,
        PEN_PRESSURE        = 1<<10,
        PEN_ORIENTATION     = 1<<11,
        PEN_PROXIMITY_ENTER = 1<<12,
        PEN_PROXIMITY_LEAVE = 1<<13,
        CLOSE_WINDOW        = 1<<14,
        QUIT_APPLICATION    = 1<<15,
        USER                = 1<<16
    };

Class 2

    enum EventType {
        EVENT_MOUSE_DOUBLE_CLICK = osgGA::GUIEventAdapter::DOUBLECLICK,
        EVENT_MOUSE_DRAG         = osgGA::GUIEventAdapter::DRAG,
        EVENT_KEY_DOWN           = osgGA::GUIEventAdapter::KEYDOWN,
        EVENT_SCROLL             = osgGA::GUIEventAdapter::SCROLL,
        EVENT_MOUSE_CLICK        = osgGA::GUIEventAdapter::USER << 1,
        EVENT_MULTI_DRAG         = osgGA::GUIEventAdapter::USER << 2,   // drag with 2 fingers
        EVENT_MULTI_PINCH        = osgGA::GUIEventAdapter::USER << 3,   // pinch with 2 fingers
        EVENT_MULTI_TWIST        = osgGA::GUIEventAdapter::USER << 4    // drag 2 fingers in different directions
    };

If I am reading this correctly the EventType::USER has a explict value of 65536 or 10000000000000000 in binary. EVENT_MULTI_TWIST has a value of 1048576 or 100000000000000000000 in binary.

What would be the purpose of assigning enum values this way over just having something like this:

enum EventType {
        NONE                = 0,
        PUSH                = 1,
        RELEASE             = 2,
        DOUBLECLICK         = 3,
        DRAG                = 4,
        MOVE                = 5,
        KEYDOWN             = 6,
        KEYUP               = 7,
        FRAME               = 8,
        RESIZE              = 9,
        SCROLL              = 10,
        PEN_PRESSURE        = 11,
        PEN_ORIENTATION     = 12,
        PEN_PROXIMITY_ENTER = 13,
        PEN_PROXIMITY_LEAVE = 14,
        CLOSE_WINDOW        = 15,
        QUIT_APPLICATION    = 16,
        USER                = 17
    };
like image 324
mdoran3844 Avatar asked Sep 17 '13 04:09

mdoran3844


People also ask

Can enum values be changed in C?

You can change default values of enum elements during declaration (if necessary).

How do you specify the size of an enum?

The C standard specifies that enums are integers, but it does not specify the size. Once again, that is up to the people who write the compiler. On an 8-bit processor, enums can be 16-bits wide. On a 32-bit processor they can be 32-bits wide or more or less.

Can enums have floating point values?

Enums can only be ints, not floats in C# and presumably unityScript.

Do C enums start at 0?

So yes, if you do not specify a start value, it will default to 0.


2 Answers

The usual reason for doing this is to associate each enum value with a single bit of a final v value, so you can (for one example) encode a number of flags into a single variable.

For example, with a typical 32-bit system, you can encode (obviously enough) 32 individual flags into a single 32-bit int (or, preferably, unsigned int).

For example, if you're looking at keys on the keyboard, you could encode "normal" keys like letters and digits into one byte (probably using consecutive values, as you've suggested), and "modifier" keys like shift, alt, and control as individual bits. This will allow you (for example) to encode something like control+alt+A as a single value.

Likewise, for mouse messages you could treat the mouse buttons as "modifiers", so you could encode something like dragging the mouse as a single value.

In both cases, the important point of encoding the "modifiers" as individual bits is that this allows you to later retrieve those modifiers unambiguously -- if the right bit is set in the value, then that modifier was use. By contrast, if you just use consecutive numbers, you can't extract individual pieces afterwards. For example, if you have inputs encoded as 1, 2 and 3, you can't tell whether a 3 is intended to indicate an original input corresponding to 3, or inputs of both 1 and 2 at the same time. If, however, you encode the values as 1, 2 and 4, you can combine values, and still decode them, so you can see exactly what input(s) were necessary to produce a particular value.

like image 106
Jerry Coffin Avatar answered Sep 23 '22 22:09

Jerry Coffin


It's one of those cases where, because a thing can be implemented in C++, no mechanism to implement it explicitly is added.

enums provide linker/debugger visible constants and can be scoped into classes and templates, so while it doesn't quite do what the end-user is trying to achieve, and certainly doesn't explicitly do it, the fact that the values in an enum expression don't have to be sequential means that it's considered sufficient for implementing enumerated bit masks.

The resulting values can be used directly in bit masks, such as:

    enum {
        Widget = 1 << 0,  // value b00000001
        Dingo = 1 << 1,   // value b00000010
        Herp = 1 << 2     // value b00000100
    };

    if (flag & Widget)
        doWidgetThings();
    if (flag & Dingo)
        feedTheDog(baby);
    if (flag & Herp)
        win();

This is capable of accepting 0, 1 or more values in "flag" at once:

    flag = 0; // matches none
    flag = Herp; // matches one flag.
    flag = Widget | Dingo; // sets flag to have both widget and dingo.
like image 33
kfsone Avatar answered Sep 21 '22 22:09

kfsone