Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign subsequent bits to C enumeration members?

Here's what I got:

enum X {
    NONE = 0x00000000,
    FLAG_1 = 0x00000001,
    FLAG_2 = 0x00000002,
    FLAG_3 = 0x00000004,
    FLAG_4 = 0x00000008,
    FLAG_5 = 0x00000010,
    // ...
    FLAG_32 = 0x80000000
}

Is there a way to make "bit numbering" automatic so I could like insert a flag so all that goes next get "renumbered"?

I'm just designing an API and I want to keep related flags together, ordered in a specific sequence. The problem is when I add something that goes in the middle I have to manually reassign all numbering that goes after the inserted item. Let's say in my example I want to add FLAG_2A = 0x00000004, and FLAG_3 should be 0x00000008 and so on. Is there a "full auto" way of doing it?

OK, here's the first thing that comes to mind:

#include <stdio.h>

enum { __FLAGS1_BASE = __COUNTER__ };
#define __FLAGS1_CT 1 << (__COUNTER__ - __FLAGS1_BASE - 1)

typedef enum __TEST1 {
    FLAG1_0 = 0,
    FLAG1_1 = __FLAGS1_CT,
    FLAG1_2 = __FLAGS1_CT,
    FLAG1_3 = __FLAGS1_CT,
    FLAG1_4 = __FLAGS1_CT
} TEST1;

enum { __FLAGS2_BASE = __COUNTER__ };
#define __FLAGS2_CT 1 << (__COUNTER__ - __FLAGS2_BASE - 1)

typedef enum __TEST2 {
    FLAG2_0 = 0,
    FLAG2_1 = __FLAGS2_CT,
    FLAG2_2 = __FLAGS2_CT,
    FLAG2_3 = __FLAGS2_CT,
    FLAG2_4 = __FLAGS2_CT
} TEST2;

int main() {
    printf("X = %u\n", FLAG2_3); // should output 4.
    return 0;
}

Is it the only way, or is there something simpler than that?

like image 282
Harry Avatar asked Oct 24 '25 16:10

Harry


1 Answers

I threw together a quick implementation of the MAKE_FLAGS macro HolyBlackCat suggested:

#define E3(...) E2(E2(E2(E2(E2(E2(E2(__VA_ARGS__)))))))
#define E2(...) E1(E1(E1(E1(E1(E1(E1(E1(__VA_ARGS__))))))))
#define E1(...) __VA_ARGS__

#define EMPTY()
#define TUPLE_AT_2(x,y,...) y

#define CHECK(...) TUPLE_AT_2(__VA_ARGS__,0,)
#define EQ_END_END ,1

#define CAT(a,b) CAT_(a,b)
#define CAT_(a,b) a##b

#define LOOP_() LOOP
#define LOOP(x,y,...) CAT(LOOP, CHECK(EQ_END_##y))(x,y,__VA_ARGS__)
#define LOOP1(x,...) 
#define LOOP0(x,y,...) y = x << 1, LOOP_ EMPTY() ()(y,__VA_ARGS__)

#define HEAD(x,...) x
#define MAKE_FLAGS(name,...) typedef enum { HEAD(__VA_ARGS__,) = 1, E3(LOOP(__VA_ARGS__, END)) } name 

MAKE_FLAGS(MyEnum, flag1, flag2, flag3, flag4);
// expands to:
// typedef enum { flag1 = 1, flag2 = flag1 << 1, flag3 = flag2 << 1, flag4 = flag3 << 1, } MyEnum;
like image 105
camel-cdr Avatar answered Oct 26 '25 07:10

camel-cdr