Mehdi Maazi
Mehdi Maazi

Reputation: 51

Using Comparison Operators in preprocessor directives C++

I want to define some functions based on a constant value:

#define mode 5

#if mode & 2 != 0
  // function 1
#endif

#if mode & 4 != 0
  // function 2
#endif

This may sound and look weird but I want to use one constant to define and activate some program modules.
defining mode = 2 includes function 1, mode = 4 includes function 2 and mode = 6 includes both functions.
There is one problem: Comparison Operators like ==, !=, > or < doesn't seem to work in directives and #if statements are always executed.

What am I doing wrong? Am I trying to do a stupid or impossible thing?

Upvotes: 0

Views: 1926

Answers (1)

KamilCuk
KamilCuk

Reputation: 141688

& has lower precendence then !=. So:

MODE & 2 != 0

is the same as

MODE & (2 != 0)

The 2 != 0 is logically true, so the result of != operator is a 1. Thus this is the same as

MODE & 1

It's just checking the first bit. While you want:

(MODE & 2) != 0

To check if the second bit is set. But really just remove the != part and do:

#if MODE & 2

Remember to prefer upper case names for macro names.

This may sound and look weird

No, that sounds completely normal. I would go with a lot more descriptive names, then plain & 2 - magic numbers are confusing. Like:

#define MODE  (MODE_ENABLE_FUNC_1 | MODE_ENABLE_FUNC_2)

#define MODE_ENABLE_FUNC_1  (1<<0)
#define MODE_ENABLE_FUNC_2  (1<<1)
#define MODE_ENABLE_FUNC_3  (1<<2)
#define MODE_IS_ENABLED(mode, feature) ( ((mode) & (feature)) != 0)
#if MODE_IS_ENABLED(MODE, MODE_ENABLE_FUNC_1)
// etc.

If possible, prefer to use C++ templates and SFINAE, rather then plain C macros.

What am I doing wrong?

You are assuming that != has lower precedence then &.

Am I trying to do a stupid or impossible thing?

No.


I remember the part The development of C language by Dennis M. Ritchie and from section name Neonatal C he writes:

[...] In converting from B to C, one wants to replace & by && in such a statement; to make the conversion less painful, we decided to keep the precedence of the & operator the same relative to ==, and merely split the precedence of && slightly from &. Today, it seems that it would have been preferable to move the relative precedences of & and ==, and thereby simplify a common C idiom: to test a masked value against another value, one must write

if ((a&mask) == b) ...

where the inner parentheses are required but easily forgotten.

No worries - you are not the first and not the last to forget about the braces in & and another operator context.

Upvotes: 5

Related Questions