Question

Flags handling in C feels cumbersome, compared to assembly.

I am looking for a way to make the C code as readable as assembly.

In Assembly:

#define powerOn flagsByte,0
... 
bsf powerOn ; Turn on the power
bcf powerOn ; Turn off the power
btfsc powerOn ; If the power is on...

In C:

flagsByte |= (1 << 0) ; // Turn on the power
flagsByte &= ~(1 << 0) ; // Turn off the power
if (flagsByte & (1 << 0)); // If the power is on...

In C, with a macro:

#define BIT_SET(var,bitNo) (var |= (1<<(bitNo)))
BIT_SET(flagsByte,0) ; // Turn on the power

That works, but it's still not as clean as in assembly.

I'd love to do:

#define powerOn flagsByte,0
BIT_SET(powerOn) ; // Turn on the power

But that doesn't work, because it expands to:

flagsByte,0 |= (1<<())

instead of:

flagsByte |= (1<<(0))

Question:

Is there an elegant way in C to set, clear or test a flag that is defined as follows?

#define powerOn flagsByte,0
Was it helpful?

Solution

Personally, I prefer the bit-field syntax, and without macros since my flags are almost always inside structs anyway. However, if you insist on writing assembler in C, here's how:

/* We need to indirect the macro call so that the pair of arguments get expanded */
#define BITSET_(f,i) do{f|= 1<<(i);}while(0)
#define BITCLR_(f,i) do{f&=~(1<<(i));}while(0)
#define BITCHK_(f,i) ((f)&(1<<(i)))

#define BITSET(fi) BITSET_(fi)
#define BITCLR(fi) BITCLR_(fi)
#define BITCHK(fi) BITCHK_(fi)

/* Define the flag container and bit number as per OP */
#define poweron flags1,0
#define warnuser flags7,4

/* Sample uses */
BITSET(poweron);
BITCLR(warnuser);
/* Since BITCHK expands to a parenthesized expression, I can get away with
 * leaving out the parentheses in the if statement. Not saying that's a good
 * idea or anything.
 */
if BITCHK(poweron) BITSET(warnuser);

If you have gcc, you can verify this with gcc -E flag_macros.c

OTHER TIPS

Here's a set of macros closely matching your assembly example:

#define powerOn        0
#define someotherfield 1

#define BITMASK(field) (1u << (field))
#define SET(field)  do { flagsByte |= BITMASK(field); } while(0)
#define CLR(field)  do { flagsByte &= ~BITMASK(field); } while(0)
#define TEST(field) (flagsByte & BITMASK(field))

/* Use examples */
SET(powerOn);
CLEAR(powerOn);
if (TEST(powerOn)) {
    // Danger!
}

Here's a variant that allows you to include the variable in the particular field definition. It's a bit tricky as it involves argument prescan

#define powerOn        flagsByte,0                                                                                                                                                      
#define someotherfield flagsByte,1                                                                                                                                                      

#define BITMASK(field) (1u << (field))                                                                                                                                                  
#define _SET(var, field)  do { var |= BITMASK(field); } while(0)                                                                                                                        
#define SET(x) _SET(x)

/* Use examples */                                                                                                                                                                      
SET(powerOn);

You could #define powerOn flagsByte |= (1 << 0); and then just use it like a statement. As in

// do stuff...
powerOn; // Turn power on.
// do stuff...

With GCC you can define so-called bit fields and manipulate them like struct members:

struct flagsByte
  {
    unsigned int powerOn: 1;  /* single bit */
  };

flagsByte.powerOn = 0;
flagsByte.powerOn = 1;

Building upon this, it is possibile to define a couple of trivial macros, reminiscent of Assembly:

#define bsf(X) flagsByte.(X) = 1
#define bcf(X) flagsByte.(X) = 0

and simply write

bsf(powerOn);  /* set flag   */
bcf(powerOn);  /* clear flag */

Unfortunately, this is not applicable to every C compiler.

You do this with a second expansion.

~/sandbox/20$ cat >t.c
#define BITSET_INNER(a,b) a |= (1<<b)
#define BITSET(spec) BITSET_INNER(spec)
#define f1 flagword,3

    BITSET(f1)

~/sandbox/20$ cc -E t.c
# 1 "t.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "t.c"




    flagword |= (1<<3)

Add token pasting and a with a strong gorge you can get some extremely gratifying results out of the C preprocessor.

You could just define some constants, not using the preprocessor but enums for fewer surprises:

enum flags{
    powerOn = 1<<0,
    powerMask = ~powerOn,
    /*...*/
};

And use them like this:

flagsByte |= power;
flagsByte &= ~power;
flagsByte &= powerMask; /* same as previous line */

A good rule of thumb in C (and C++): Do not use the preprocessor if you can avoid it.

Anyway, if you can live with the inherent implementation-definedness of bitfields, use bitfields as Roberto Reale proposes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top