4

It's common to perform a check and set/clear a flag, eg:

if (some_test) {
   flag |= SOME_FLAG;
}
else {
   flag &= ~SOME_FLAG;
}

A convenient way around this I found so far is...

flag = (some_test) ? (flag | SOME_FLAG) : (flag & ~SOME_FLAG);

This could be made into a macro and its OK, but is there some bit-twiddeling magic to avoid referencing flag twice?

(in case multiple instantiations of flag causes overhead).

Example of what I'm looking for (if C could do ternary operations on operators), is...

flag ((some_test) ? (|=) : (&= ~) SOME_FLAG;

The example above is only to describe what I'm looking for, of course it wont work in its current form.

ideasman42
  • 42,413
  • 44
  • 197
  • 320

3 Answers3

8
flag |= SOME_FLAG

is an expression, so you can use a macro

#define SET_FLAG(flag, some_test) \
    ((some_test) ? ((flag) |= SOME_FLAG) : ((flag) &= ~SOME_FLAG))

which evaluates flag only once, and when you use it, you need to type flag only once.

SET_FLAG(a->b->c->d, test);
Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • Thanks, makes sense, this looks like the best option. I was wondering if there was some combination of bitmasking operators that could do this neatly (with a single operator), but seems not. – ideasman42 Nov 07 '12 at 06:47
  • there is if you think about introducing variable length bitshifts (<< and >>) and detecting which power of 2 your flag is... but there is little benefit to that, its more complicated and less performant. certainly not a succinct solution – jheriko Nov 09 '12 at 14:04
3

I know you don't want to access flag twice. But you should be sure that is where the cost is. Often, the conditional jump is more expensive. On the last embedded processor I worked on, the fastest code would have looked like this:

 flag &= ~(SOME_FLAG);
 flag |= (some_test!=0) * SOME_FLAG;
AShelly
  • 34,686
  • 15
  • 91
  • 152
  • note however that on many common platforms (x86, ppc, arm) ?: compiles to a conditional move rather than branching - which can be cheaper than an integer multiply – jheriko Nov 09 '12 at 14:05
0

If you want to define a macro and have it avoid evaluating the mask twice then you could do it like this:

#define SETT(FLAG, MASK_T, MASK, TEST) \
do {\
  MASK_T mask = (MASK);\
  FLAG &= ~mask;\
  FLAG |= ((TEST) != 0) * mask;\
}\
while(false)

#define SET(FLAG, MASK, TEST) SETT(FLAG, unsigned, MASK, TEST)
Pubby
  • 51,882
  • 13
  • 139
  • 180
  • disadvantage with this is it does multiple writes to FLAG that the compiler may not optimize out. – ideasman42 Nov 07 '12 at 13:22
  • @ideasman42 The conditional is going to be slower than an extra bitwise op. – Pubby Nov 07 '12 at 13:32
  • maybe (though the conditional could evaluate to a constant too - so not necessarily) - but you can still evaluate that once and apply the bitwise op once too - other examples given here do it. – ideasman42 Nov 08 '12 at 05:22