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...
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.
Related
I want to create a macro that converts unsigned value conv to the opposite byte order of the current CPU. When not in a macro, it works well but let's say I want to do that as a macro. The compiler throws me an implict decleration when I try to use the macro. Take in mind that cpu_to_be32 and friends is a kernel-space functions, afaik at least.
#define be32_or_le32(conv) do { #ifdef __LITTLE_ENDIAN \
conv = cpu_to_be32(conv); \
#elif __BIG_ENDIAN \
conv = cpu_to_le32(conv); \
#endif } while (0)
u32 x = 0x12345678;
/* Convert the CPU's default byteorder to the opposite one */
be32_or_le32(x); /* Implict decleration */
Update: The answer below works really well but only without the do {} while (0), why when do.. added an error is thrown?
#ifdef __LITTLE_ENDIAN
#define be32_or_le32(conv) do { conv = cpu_to_be32(conv); } while (0)
#elif __BIG_ENDIAN
#define be32_or_le32(conv) do { conv = cpu_to_le32(conv); } while (0)
#endif
int __init sys_kernelmod_init(void)
{
u32 conv;
u32 x = 0x12345678;
/* Convert the CPU's default byteorder to the opposite one */
conv = be32_or_le32(x);
...
}
Don't use macros for things like this - use "static inline" functions. And try to give more sensible names - you are swapping the bytes in the 32-bit value, so it is a "byte swap" function. It is completely independent of the endianness of the system as you are always reversing the endianness, so there is no need to do any kind of conditional compilation. And stick to the standard type names (such as "uint32_t"), not home-made names (like "u32"), unless you have very good reason.
uint32_t bswap32(uint32_t x) {
return ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24));
}
Any decent compiler will optimise this to a single instruction if the target processor has a byte-swap instruction.
You cannot have preprocessor conditionals inside the macro expansion text.
Switch the structure to:
#ifdef __LITTLE_ENDIAN
#define be32_or_le32(conv) do { conv = cpu_to_be32(conv); } while (0)
#elif __BIG_ENDIAN
#define be32_or_le32(conv) do { conv = cpu_to_le32(conv); } while (0)
#endif
In my Arduinoc (cpp) code, I have these macros that set/clear bit y of register x:
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
In several places I then use:
CLEAR(PORTB,7)
or
SET(PORTB,7)
I would like to define a macro to be PORTB,7 so it only appear once, in a header file, not all over my code. (I show only one example, but I have several conbinations of PORTx,N in my code).
I tried:
#define CLOCK PORTB,7
#define CLOCK_HIGH SET(CLOCK)
but it then fails to build with:
error: macro "SET" requires 2 arguments, but only 1 given CLOCK_HIGH; delay(DELAY); CLOCK_LOW; delay(DELAY);
Is there a way to achieve that?
You must first expand the macro inside. Ie. do another pass. Your code may look like this:
#define SET(x,y) do{ (x) |= (1u << (y)); }while(0)
#define CLEAR(x,y) do{ (x) &= ~(1u << (y)); }while(0)
#define HIGH(a) SET(a) // another empty pass, just forward
// the `a` is expanded and the second `SET` takes two arguments
// or better, but not fully compliant:
// #define HIGH(...) SET(__VA_ARGS__)
#define CLOCK PORTB, 7
#define CLOCK_HIGH() HIGH(CLOCK)
int main() {
int PORTB;
CLOCK_HIGH();
}
As a good measure research about macro pitfalls and research good practices when writing macros..
I want to be able to define a tuple which represents the arguments needed by other macros.
I think the best way to show what I want is to show an example:
#include <avr/io.h>
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PB7
#define LED LED_PORT, LED_DDR, LED_PIN
#define OUTPUT(port, ddr, pin) ddr |= 1 << pin
void main(void) {
OUTPUT(LED);
}
I want OUTPUT(LED) to be then expanded into:
LED_DDR |= 1 << LED_PIN
The problem that I get is to do with the order of expansion, and results in the following error:
macro "OUTPUT" requires 3 arguments, but only 1 given
This is for use with an AVR project with custom built hardware where I have defined LED and other components with a respective LED_PORT LED_DDR and LED_PIN.
I then want to define more macros that can take this LED and use the appropriate arguments to map to the most succinct way possible.
Is this possible with the standard C-preprocessor?
You can add a level of indirection to the macro to achieve this:
#define OUTPUT_I(port, ddr, pin) ddr |= 1 << pin
#define OUTPUT(spec) OUTPUT_I(spec)
During rescanning, spec is expanded before OUTPUT_I, so the OUTPUT_I macro sees three parameters.
I want to be able to define a tuple which represents the arguments needed by other macros.
I think the best way to show what I want is to show an example:
#include <avr/io.h>
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PB7
#define LED LED_PORT, LED_DDR, LED_PIN
#define OUTPUT(port, ddr, pin) ddr |= 1 << pin
void main(void) {
OUTPUT(LED);
}
I want OUTPUT(LED) to be then expanded into:
LED_DDR |= 1 << LED_PIN
The problem that I get is to do with the order of expansion, and results in the following error:
macro "OUTPUT" requires 3 arguments, but only 1 given
This is for use with an AVR project with custom built hardware where I have defined LED and other components with a respective LED_PORT LED_DDR and LED_PIN.
I then want to define more macros that can take this LED and use the appropriate arguments to map to the most succinct way possible.
Is this possible with the standard C-preprocessor?
You can add a level of indirection to the macro to achieve this:
#define OUTPUT_I(port, ddr, pin) ddr |= 1 << pin
#define OUTPUT(spec) OUTPUT_I(spec)
During rescanning, spec is expanded before OUTPUT_I, so the OUTPUT_I macro sees three parameters.
I want to define some constants in my C file.
Its assembly code like this:
Const1 = 0
Const2 = 0
IF Condition1_SUPPORT
Const1 = Const1 or (1 shl 6)
Const2 = Const2 or (1 shl 3)
ENDIF
IF Condition2_SUPPORT
Const1 = Const1 or (1 shl 5)
Const2 = Const2 or (1 shl 2)
ENDIF
Could you tell me the simplest way to implement this?
And it should be flexible enough because the number of both my constants and conditions is over 10.
After seeing the first three answers, I guess I need to explain more;
What I want to know is how to redefine my constant based on its previous value.
You can do so using preprocessing directives:
#if Condition1_SUPPORT
#define Const1 (1 << 6)
// ...
#elif Condition2_SUPPORT
#define Const1 (1 << 5)
// ...
#endif
To address the edit to the question: you can't redefine a macro based on its previous value. A macro can only have one value at a time and its replacement list is only evaluated when it is invoked, not when it is defined. For example, this is not possible:
#define A 10
#define A A + 10
First, it is an illicit redefinition of the macro: when the second line is handled, A is already defined as a macro, and so it cannot be redefined with a different replacement (you have to #undef the macro name first).
Second, were this licit (and many compilers do accept it), the second line, when invoked, would evaluate to A + 10, not 10 + 10 or 20 as you want: by the time the second macro definition could be invoked, the first definition no longer exists.
You can, however, use different names, like so:
#define INITIAL_A 10
#define A INITIAL_A + 10
You should consider getting one of the introductory books from The Definitive C Book Guide and List; any of them would cover what can be accomplished using the preprocessing directives in some detail.
You can't redefine the value of a constant once you assign it -- if you could, it wouldn't be a constant, would it? Since it looks like you're trying to set various bits in a constant based on preprocessor flags, you could #define separate constants for each condition's contribution, then build the final value at the end:
#if Condition1_SUPPORT
# define Const1_Cond1_Bit (1 << 6)
# define Const2_Cond1_Bit (1 << 3)
#else
# define Const1_Cond1_Bit (0)
# define Const2_Cond1_Bit (0)
#endif
#if Condition2_SUPPORT
# define Const1_Cond2_Bit (1 << 5)
# define Const2_Cond2_Bit (1 << 2)
#else
# define Const1_Cond2_Bit (0)
# define Const2_Cond2_Bit (0)
#endif
#define Const1 (Const1_Cond1_Bit | Const1_Cond2_Bit)
#define Const2 (Const2_Cond1_Bit | Const2_Cond2_Bit)
You can then #undef all the intermediate constants, if namespace pollution is a concern.
You can use pre processor macros to conditionally define a constant variable, like
#if SOME_CONDITION
const int my_constant = 10;
#else
const int my_constant = 5;
#endif
In C, you would use preprocessor macros to accomplish that:
#ifdef COND1_SUPPORT
#define CONST1 CONST1_VAL1
#define CONST2 CONST2_VAL1
#elif COND2_SUPPORT
#define CONST1 CONST1_VAL2
#define CONST2 CONST2_VAL2
#endif