C ++ Assignment of Enumeration Cells Using Bit Offset

I looked through some code from open source projects and noticed that for more than one case, enumeration values ​​were assigned by bit shifting the values ​​in increasing number of places. I see no specific reason for this, and I see no improvement in efficiency when assigning values, just increasing +1.

Despite this, it hardly makes sense without any code to demonstrate what confused me.

Grade 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 read this correctly, EventType :: USER has an expressed value of 65536 or 10000000000000000 in binary format. EVENT_MULTI_TWIST is set to 1048576 or 100000000000000000000 in binary format.

What would be the purpose of assigning enum values ​​this way, 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 }; 
+4
source share
3 answers

A common reason for this is to associate each enumeration value with one bit of the final value of v, so you can (for one example) encode multiple flags into one variable.

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

For example, if you look at the keys on the keyboard, you can encode the “regular” keys, such as letters and numbers, in one byte (possibly using sequential values, as you suggested), and the “modifier” keys, such as shift , alt and control as separate bits. This will allow you (for example) to encode something like control + alt + A as a single value.

Similarly, for mouse messages, you can think of the mouse buttons as “modifiers,” so you can encode something like dragging the mouse as a single value.

In both cases, an important point of encoding “modifiers” as individual bits is that it allows you to subsequently get these modifiers unambiguously - if the correct bit is set to, then this modifier was used. In contrast, if you just use sequential numbers, you cannot retrieve individual parts afterwards. For example, if you have inputs encoded as 1 , 2 and 3 , you cannot determine whether 3 indicate the original input corresponding to 3 , or inputs as 1 and 2 at the same time. If, however, you encode the values ​​as 1 , 2 and 4 , you can combine the values ​​and decode them so that you can see exactly what input is needed to create a specific value.

+8
source

This is one of those cases where, since a thing can be implemented in C ++, no mechanism is added to explicitly add it.

enumerations provide visible linker / debugger constants and can be covered by classes and templates, therefore, although it doesn’t quite do what the end user is trying to achieve, and, of course, doesn’t explicitly do this, the fact that the values ​​in the enum expression do not have to to be consistent means that it is considered sufficient to implement the enumerated bit masks.

The resulting values ​​can be used directly in bit masks, for example:

  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 able to take values ​​of 0, 1 or more in the "flag" at the same time:

  flag = 0; // matches none flag = Herp; // matches one flag. flag = Widget | Dingo; // sets flag to have both widget and dingo. 
+3
source

The reason you want to do this is because you can use enums defined in such a way as bitmasks. Given a 32-bit integer, you can have 32 unique properties that could be turned on or off using bit-mutated combinations of the listed values.

For example, if you want to create an event handler that listened for QUIT_APPLICATION and CLOSE_WINDOW in an implementation that uses bit shifts, you can simply use QUIT_APPLICATION | CLOSE_WINDOW QUIT_APPLICATION | CLOSE_WINDOW . Each enumeration is a single bit, and combining them together makes it easy to specify all the types of events that you wanted, in a way that you could not do if they were simply enumerated from 1-16.

Think about where you wanted an event handler that listened to PUSH and RELEASE using the proposed "more efficient" enumeration. If you were with them, you would get 3 . 3 also the DOUBLECLICK value in your example. Therefore, there is no way to find out what events you really wanted; Was it a combination of PUSH and RELEASE , or is it just DOUBLECLICK ? Therefore, the reservation of one bit for each of the listed types is so powerful.

You will often see the listed values, defined as follows:

 enum EventType { NONE = 0, PUSH = 0x1, RELEASE = 0x2, DOUBLECLICK = 0x4, DRAG = 0x8, MOVE = 0x10, KEYDOWN = 0x20, KEYUP = 0x40, FRAME = 0x80, RESIZE = 0x100, SCROLL = 0x200, PEN_PRESSURE = 0x400, PEN_ORIENTATION = 0x800, PEN_PROXIMITY_ENTER = 0x1000, PEN_PROXIMITY_LEAVE = 0x2000, CLOSE_WINDOW = 0x4000, QUIT_APPLICATION = 0x8000, USER = 0x10000 }; 

Sometimes you will even see things like:

  ... CLOSE_WINDOW = 0x4000, QUIT_APPLICATION = 0x8000, CLOSE_AND_QUIT = CLOSE_WINDOW | QUIT_APPLICATION, ... 

The bitrate designation is easier to read (for some people), they both do the same. Each enumerated value is a one-bit or discrete combination of bits (except for NONE , which represents the absence of all bits).

+2
source

Source: https://habr.com/ru/post/1502534/


All Articles