Reputation: 51
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
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