I'm trying to write a macro which simplifies setting multiple bits in an integer. This commonly occurs in microcontroller code when initializing configuration registers. For example, one might configure an 8-bit timer by setting 3 bits in the register TCCR0A like this:
// WGM01, WGM00 and COM0A1 are constants between 0 and 7 // There are hundreds of these constants defined in avr-libc TCCR0A |= (1<<WGM01) | (1<<WGM00) | (1<<COM0A1); // Another way to write this: #define _BV(bit) (1 << (bit)) // <-- defined in avr-libc TCCR0A |= _BV(WGM01) | _BV(WGM00) | _BV(COM0A1); However, I'd find it a lot easier to write something like this:
TCCR0A |= BITS(WGM01, WGM00, COM0A1); // <- Variable # of arguments please! Since I can't imagine that nobody has thought of this yet, I searched around but found nothing which does exactly this. I wonder if this is possible at all, but I gave it a shot anyways while reading https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html and https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms.
Here's what I tried so far. I imagine the solution must be recursive macro, but didn't get very far when trying to get it to expand correctly. Since all my registers are 8 bits long, 8 expansion passes should be sufficient (for a first try).
#define BITS_EVAL(...) BITS_EVAL1(BITS_EVAL1(BITS_EVAL1(__VA_ARGS__))) #define BITS_EVAL1(...) BITS_EVAL2(BITS_EVAL2(BITS_EVAL2(__VA_ARGS__))) #define BITS_EVAL2(...) __VA_ARGS__ #define BITS(bit, ...) ((1 << bit) | BITS_EVAL(BITS(__VA_ARGS__))) The above doesn't quite work. What it currently does is:
// BITS(2,5,7) --> ((1 << 2) | BITS(5, 7)) However, what I would like to achieve is one of these (or equivalent):
// BITS(2,5,7) --> ((1 << 2) | (1 << 5) | (1 << 7)) // BITS(2,5,7) --> ((1 << 2) | ((1 << 5) | ((1 << 7)))) Can anyone help me with my quest, or tell me that it's impossible to achieve this?
(1 << bit)-->>(1u << bit). It helps. Sometimes.enum { BM_WGM01 = 1 << WGM01, BM_WGM00 = 1 << WGM00, BM_COM0A1 = 1 << COM0A1 … };or a more formally typed mechanism equivalent to that (one that specifies the size of the values, probably ensuring they are unsigend), and then write:TCCR0A |= BM_WGM01 | BM_WGM00 | BM_COM0A1;, couldn't you?(1<<a) | (1<<b)bitwise arithmetic rather than fancy macros that you have to find and understand before reading the actual code. Also, macros can be overridden.a |= BIT1 | BIT2 ...;Don't use macros unless they enhance code quality (which includes readability).