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;
}