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
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
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With