News for hackers. Stuff that matters.
Re:Type-safe Bitmasks in C++ by pdkl95 on Wednesday June 13, 2018 @09:15AM (#17302714)
> Note that we don't explicitly set [enum values] to be powers of two

> return 1 << static_cast<underlying_type>(o);

Relying on default enum values to and automagically converting these into power of two bit masks is very brittle, and can create unexpected bugs and interoperability problems. The mask values change if the enum changes, unused bits in the middle of the bitmask are hard to handle, and the bit order is assumed with the first item being the LSB. The last point is particularly relevant given the NES buttons example, because it uses a bit order opposite to how the controller data is usually read[1]. This article defines

    #define BTN_A      0x01  /* 00000001 in binary */
    #define BTN_B      0x02  /* 00000010 in binary */
    /* ... */
    #define BTN_RIGHT  0x80  /* 10000000 */
The standard controller[2] state is sent from a shift register in the controller one bit at a time. This is usually read by the program as 8 reads from the I/O port, and shifted into a button state bitmask. E.g. something like:

    n = 8;
    buttons = 0;
    while(buttons--) {
        buttons = buttons << 1;
        buttons |= (CONTROLLER_1_IO_PORT & 0x01);
    }
With the buttons being read in the order [A, B, ..., RIGHT], the recommended bitmask is:

    BUTTON_A        = 1 << 7
    BUTTON_B        = 1 << 6
    /* ... */
    BUTTON_RIGHT    = 1 << 0
Obviously this is a minor mistake in a (probably untested) example. I just want to highlight how easily this type of "clever" - but brittle - coding style can introduce errors. Defining bit values (and other externally defined magic numbers) explicitly in e.g. a defined-to-be-canonical header file (which might be just those 8 #defines) is much safer and easier to debug/maintain. Then wrap those explicitly defined values into the C++ template for type safety or other fancy features.

[1] https://wiki.nesdev.com/w/index.php/Controller_Reading

[2] https://wiki.nesdev.com/w/index.php/Standard_controller

Re:Type-safe Bitmasks in C++ by pubby on Wednesday June 13, 2018 @09:34AM (#17302861)
Oh, the NES controller bit order is 100% arbitrary. There's no standard - it all depends on if the programmer decided to write a ROL or ROR instruction that day.

But I agree with your point.

Re:Type-safe Bitmasks in C++ by unwind on Wednesday June 13, 2018 @01:13PM (#17305070)
You meant:

    while (n--)
Re:Type-safe Bitmasks in C++ by theincredulousk on Wednesday June 13, 2018 @04:26PM (#17306631)
Defining bit values (and other externally defined magic numbers) explicitly in e.g. a defined-to-be-canonical header file (which might be just those 8 #defines) is much safer and easier to debug/maintain

I'm all for modern C++, but this is correct, at least IME with embedded systems. You're overall better off sticking with C-style if working at an abstraction level where the interface itself uses bitmasks. At this point you're manipulating memory manually which is (a) C's wheelhouse and (b) where type safety becomes largely irrelevant.

There is a lot to be said for using custom enum class implementations (e.g. http://www.drdobbs.com/when-enum-just-isnt-enough-enumeratio...) but it isn't clear to me how this kind of thing benefits bitmasks when the goal is presumably absolute maximum efficiency.