Search code examples
cc-preprocessorflags

Setting a flag in C as elegantly as in assemby language


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

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