Bitmask switch statement

No it's not a clean solution and for your context, you can avoid mixing #define and functions. You can try below solution, if you want switch():

int bitmask = val1 | val3;
int mask = 1;
while(bitmask)
{
  switch(bitmask & mask)
  {
  case val1: ... break;
  case val2: ... break;
  case val4: ... break;
  case val8: ... break;
  }
  bitmask &= ~mask; 
  mask <<= 1;
}

No, it is (obviously) not a clean solution. Your original code was straight-forward, didn't loop, and didn't involve special-case "secret" macros that add weird constructs to the language.

By "weird construct", I meant the START_BITMASK_SWITCH()/END_BITMASK_SWITCH macros, which:

  • Add a loop without using any of the standard keywords to even hint that a loop is happening
  • Clobber names in the current scope more or less silently
  • Include a spurious semi-colon

There's no benefit to your solution, all it does is add bloat and overhead (both in terms of code size, and complexity, and run-time performance) just to scratch that itch of for some reason wanting to use a switch to do something that it's not very well-suited to do.

Obviously, this is highly subjective, but you did ask.


I see several problems:

  • it adds preprocessor cruft with no real benefit
  • it adds a lot of slow code (shifts, loops, tests)
  • it prevents you from adding special cases such as "if bit 2 is on and bit 3 is off" (if ((bitmask & (val2 | val3)) == val2))
  • the compiler will miss almost every possibility to optimise the generated code

It can also be done in a much, much simpler way:

#define START_BITMASK_SWITCH(x) \
    for (uint64_t bit = 1; x >= bit; bit *= 2) if (x & bit) switch (bit)

int bitmask = val1 | val3;

START_BITMASK_SWITCH(bitmask)
{
    case val1:
        ...
        break;
    case val2:
        ...
        break;
    case val3:
        ...
        break;
}