In C, it's common to declare an enum as a bunch of flags:
typedef u32 MyFlags; enum { A = 1 << 0, // 1 B = 1 << 1, // 2 C = 1 << 2, // 4 };
Is there any way to get back the flag's position from these enums at compile time?
GetFlagPos(A) // 0 GetFlagPos(B) // 1 GetFlagPos(C) // 2 // not 1, 2, 4
The reason I want this is because:
flags |= value << GetFlagPos(A)
value *= myTable[GetFlagPos(C)] // element 2 not 4
Maybe there is a better way but this seems to work (only if you pass it a enum label or a number literal. Otherwise it won't be compile time.
#define flag_bit_index( flag ) \ ( flag & 0x2 ) ? 1 : \ ( flag & 0x4 ) ? 2 : \ ( flag & 0x8 ) ? 3 : \ ( flag & 0x10 ) ? 4 : \ ( flag & 0x20 ) ? 5 : \ ( flag & 0x40 ) ? 6 : \ ( flag & 0x80 ) ? 7 : \ ( flag & 0x100 ) ? 8 : \ ( flag & 0x200 ) ? 9 : \ ( flag & 0x400 ) ? 10 : \ ( flag & 0x800 ) ? 11 : \ ( flag & 0x1000 ) ? 12 : \ ( flag & 0x2000 ) ? 13 : \ ( flag & 0x4000 ) ? 14 : \ ( flag & 0x8000 ) ? 15 : \ ( flag & 0x10000 ) ? 16 : \ ( flag & 0x20000 ) ? 17 : \ ( flag & 0x40000 ) ? 18 : \ ( flag & 0x80000 ) ? 19 : \ ( flag & 0x100000 ) ? 20 : \ ( flag & 0x200000 ) ? 21 : \ ( flag & 0x400000 ) ? 22 : \ ( flag & 0x800000 ) ? 23 : \ ( flag & 0x1000000 ) ? 24 : \ ( flag & 0x2000000 ) ? 25 : \ ( flag & 0x4000000 ) ? 26 : \ ( flag & 0x8000000 ) ? 27 : \ ( flag & 0x10000000 ) ? 28 : \ ( flag & 0x20000000 ) ? 29 : \ ( flag & 0x40000000 ) ? 30 : \ ( flag & 0x80000000 ) ? 31 : \ ( flag & 0x100000000 ) ? 32 : \ ( flag & 0x200000000 ) ? 33 : \ ( flag & 0x400000000 ) ? 34 : \ ( flag & 0x800000000 ) ? 35 : \ ( flag & 0x1000000000 ) ? 36 : \ ( flag & 0x2000000000 ) ? 37 : \ ( flag & 0x4000000000 ) ? 38 : \ ( flag & 0x8000000000 ) ? 39 : \ ( flag & 0x10000000000 ) ? 40 : \ ( flag & 0x20000000000 ) ? 41 : \ ( flag & 0x40000000000 ) ? 42 : \ ( flag & 0x80000000000 ) ? 43 : \ ( flag & 0x100000000000 ) ? 44 : \ ( flag & 0x200000000000 ) ? 45 : \ ( flag & 0x400000000000 ) ? 46 : \ ( flag & 0x800000000000 ) ? 47 : \ ( flag & 0x1000000000000 ) ? 48 : \ ( flag & 0x2000000000000 ) ? 49 : \ ( flag & 0x4000000000000 ) ? 50 : \ ( flag & 0x8000000000000 ) ? 51 : \ ( flag & 0x10000000000000 ) ? 52 : \ ( flag & 0x20000000000000 ) ? 53 : \ ( flag & 0x40000000000000 ) ? 54 : \ ( flag & 0x80000000000000 ) ? 55 : \ ( flag & 0x100000000000000 ) ? 56 : \ ( flag & 0x200000000000000 ) ? 57 : \ ( flag & 0x400000000000000 ) ? 58 : \ ( flag & 0x800000000000000 ) ? 59 : \ ( flag & 0x1000000000000000 ) ? 60 : \ ( flag & 0x2000000000000000 ) ? 61 : \ ( flag & 0x4000000000000000 ) ? 62 : \ ( flag & 0x8000000000000000 ) ? 63 : 0
Why do you want flag position to be compile time value?
Classically you would typically do this:
enum { A_INDEX = 0, B_INDEX = 1, C_INDEX = 2, }; enum { A = 1 << A_INDEX, B = 1 << B_INDEX, C = 1 << C_INDEX, };
Then you can do flags |= value << A_INDEX;
And you can do #define FLAG(x) (1 << (x))
then you can write FLAG(A_INDEX)
and not use those preshifted enum values.
But on modern compilers you can simply do flags |= value * A;
Compiler will optimize to same shift, no multiplication will be involved.
Also what exactly is value
? if it is boolean you want to set flag A or not, then you can simply write flags |= (value ? A : 0)
and no need to worry about bit positions or shifts.
And if you're fine with value not to be compile time value, you can calculate bit position from flag value with very simple operation:
int GetFlagPos(MyFlags flag) { assert(flag != 0); unsigned long index; _BitScanForward(&index, flag); return index; }
Then you can do value *= myTable[GetFlagPos(C)];
That'll cost just one extra simple operation.
flags |= (value ? A : 0)
is what I ended up doing, but isn't a runtime unpredictable check slower than a left shift?
Talking about compile-time value makes me wonder: Is the compiler required by the C spec to return compile-time value? For example, with int a = 5 + 3
, can the compiler allow to produce an add
?
By "unpredictable check" you mean "unpredictable branch" ? There will be no branch. It will compile to exactly same code with few simple bitwise operations - in all cases, be it conditional operation, manual shift, or with multiplication.
See here: https://godbolt.org/z/5rG39oj6f
Identical code for all three functions.
if you write int a = 5 + 3;
then compiler is allowed to do either - leave 5 + 3
as runtime operation, or just produce 8
. In either case variable a
won't be compile time value. It's a variable, so you won't be able to use it where compile time constants are expected.
If you want to force compiler to produce compile time value, the typical trick in C is to use enum: enum { a = 5 + 3 };
Now a
is compile time value. In C++ you can use constexpr
for same effect.