2

I'm beginning to learn programming embedded C micro-controllers and want to do something that would make my life easier. Usually when dealing with bit masking everybody uses stuff like:

char a = (1 << 3) | (1 << 1) | (1 << 5);

I want to use a macro for something like this. For just one mask I can simply define this macro:

#define M(n) (1 << (n))

Nothing fancy. The problem is that I cannot come with a good solution that would allow me to type:

a = MM( 3, 1, 5 ); or at least a = MM( 3, 3, 1, 5 ); (where the first 3 is the number of arguments)

instead of a = M(3) | M(1) | M(5);

I came up with a solution which implied using functions with multiple arguments but it's really bugging me that I cannot do it using a macro.

nicusor
  • 338
  • 1
  • 10
  • Of course I can. `#define MM( nr, args... ) //whatever` Check out variadic macros. – nicusor Jul 09 '14 at 19:33
  • 2
    Take a look inside common MCU headers to see good macro examples. You also seem to want to be a little too fancy. For example, in my msp430 project, somewhere there's a bunch of `#define BIT0 1<<0`, `#define BIT1 1<<1`, so on...and it's perfectly readable, and preferred, to see code like `P1OUT = BIT1 | BIT2 | BIT3`. And you can use these to define more complex masks that you might use regularly. – Ben Jul 09 '14 at 19:35
  • 1
    See this previous answer: http://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros – JohnH Jul 09 '14 at 19:38
  • I understand that my wishes might be a little to fancy, yet I view this problem more as an interesting puzzle instead of just need for good code. – nicusor Jul 09 '14 at 19:41

3 Answers3

2

Found the answer.

#define M(a)        (1 << (a))
#define M2(a, b)    (M(a) | M(b))
#define M3(a, b...) (M(a) | M2(b))
#define M4(a, b...) (M(a) | M3(b))
// can be continued

#define GET_MACRO( _1, _2, _3, _4, NAME, ... ) NAME
#define MM(args...) GET_MACRO( args, M4, M3, M2, M )(args)

this uses the answer in this thread

Community
  • 1
  • 1
nicusor
  • 338
  • 1
  • 10
  • 3
    This is not valid C syntax, but uses a gcc extension. It should just have `M3(a, ...)` and `MM(...)` and use `__VA_ARGS__` instead of `b` or `args`. – Jens Gustedt Jul 09 '14 at 20:47
1

Maybe this can help:

#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK(x,y) ((x) & (y))
Dr. Sahib
  • 156
  • 10
0

use boost

#include <boost/preprocessor/tuple/to_seq.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/control/if.hpp>

#define M(n) (1 << (n))
#define F(r, data, i, elem) BOOST_PP_IF(i, data, ) M(elem)
#define MM(...) BOOST_PP_SEQ_FOR_EACH_I(F, | , BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__)) )

...
char a = MM(3, 1, 5);//char a = (1 << (3)) | (1 << (1)) | (1 << (5)) ;
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70