Home > Software engineering >  How to "#define" multiple values then "#if" them in C
How to "#define" multiple values then "#if" them in C

Time:11-10

The following code does not work but demonstrates what I want to do

#define TESTINGMACRO 2 | 3

#if TESTINGMACRO & 1 //Should be inactive
#endif

#if TESTINGMACRO & 2 //Should be active
#endif

#if TESTINGMACRO & 3 //Should be active
#endif

Another alternative:

#define TESTINGMACRO 2, 3

#if TESTINGMACRO == 1 //Should be inactive
#endif

#if TESTINGMACRO == 2 //Should be active
#endif

#if TESTINGMACRO == 3 //Should be active
#endif

I know an enum or an array would work too however some preprocessor blocks contains #includes that might not build. Using preprocessor code allows for testing the rest of the file.

I also know I can do the following but this will be a large file so a single central macro would be cleaner:

#define TESTINGMACRO2
#define TESTINGMACRO3

#ifdef TESTINGMACRO1 //Should be inactive
#endif

#ifdef TESTINGMACRO2 //Should be active
#endif

#ifdef TESTINGMACRO3 //Should be active
#endif

Edit: Just FYI in the first scenario all preprocessor blocks are active in practice. So doing 2 | 3 will activate & 1 as well. This is the case for the second code snippet too. This is not what I want, only 2 and 3 should be active when 2|3.

Edit2: I ended up doing:

#define BIT(n)  (1<<n)

#define TESTINGMACRO  ( BIT(2) | BIT(3) )

#if TESTINGMACRO & BIT(1) //Inactive
#endif

#if TESTINGMACRO & BIT(2) //Active
#endif

#if TESTINGMACRO & BIT(3) //Active
#endif

Format wise this is closest to my original and in my opinion quite readable. Thanks for all the help

CodePudding user response:

You can use bit fields — but then you need to do it properly:

  • Define the values as distinct powers of two. Instead of 1, 2, 3, …, use 1 << 0, 1 << 1, 1 << 2, … (aka. 1, 2, 4 …).

  • Fix the operator precedence by adding parentheses. Remember that macros are expanded via textual replacement.

#define TESTINGMACRO ((1 << 1) | (1 << 2))

#if TESTINGMACRO & (1 << 0) //Should be inactive
#endif

#if TESTINGMACRO & (1 << 1) //Should be active
#endif

#if TESTINGMACRO & (1 << 2) //Should be active
#endif

That said, I would generally recommend using separate feature macros instead, the resulting code is more readble.

CodePudding user response:

#define TESTINGMACRO1
#define TESTINGMACRO2
#define TESTINGMACRO3

#ifdef TESTINGMACRO1 //Should be inactive
#endif

#ifdef TESTINGMACRO2 //Should be active
#endif

#ifdef TESTINGMACRO3 //Should be active
#endif

Just do it. There isn't a better way. This really is what everybody expects.

The actual reason your didn't work is really quite simple though.

#define TESTINGMACRO 2 | 3

is not correct because of operator precedence. It should be

#define TESTINGMACRO (2 | 3)

As Konrad Rudolph has pointed out, 3 isn't a single bit and you probably intended 4. Some people recommend (1 << n) to get the bits, but I normally use hex constants. 0x04, 0x08, 0x10 is easy enough to read.

In theory you can only have 15 bits (signed-ness) before you run into trouble, but in practice it will work for 32 bits because you will almost never encounter a 16 bit host compiler anymore.

CodePudding user response:

The main problem with your approach is that you're using values that have common bits set. Each value should correspond to a single bit. Then you can check for that bit. You've also got a precedence problem since & has higher precedence than |.

So instead of 1, 2, and 3 for values you want 1, 2, and 4 (or equivalently, 1<<0, 1<<1 and 1<<2).

#define TESTINGMACRO ((1<<1) | (1<<2))

#if TESTINGMACRO & (1<<0) //Should be inactive
#endif

#if TESTINGMACRO & (1<<1) //Should be active
#endif

#if TESTINGMACRO & (1<<2) //Should be active
#endif
  • Related