6

Is it possible to define a C/C++ macro "BUILD(a, i)" which expands to "x[0], x[1], x[2], ..., x[i]" ? Like in

#define BUILD(x, 0) x[0]
#define BUILD(x, 1) x[0], x[1]
#define BUILD(x, 2) x[0], x[1], x[2]
...

It seems BOOST_PP_ENUM_PARAMS could do the job. I suppose I could just #include boost, but I'm interested in knowing how and why it works, anyone can explain?

I would like to call a function f(int, ...) which takes N int arguments x[i], 0 <= i < N. Where N is known to be ceil(sizeof(A) / sizeof(B)). So unfortunately, I cannot use varargs or templates.

a3f
  • 8,517
  • 1
  • 41
  • 46
Giovanni Funchal
  • 8,934
  • 13
  • 61
  • 110
  • related: http://stackoverflow.com/questions/824639/variadic-recursive-preprocessor-macros-is-it-possible/893684 – Nick Dandoulakis Aug 17 '09 at 09:34
  • What problem are you really trying to solve? ie. what will the result of this macro be used for? Could the usage be changed slightly to allow for a template solution (where recursion is possible)? – Richard Corden Aug 17 '09 at 10:36
  • so why not just pass the array? or better still a vector? –  Aug 17 '09 at 11:00

3 Answers3

15

It is possible, but you have to do some manual work and have an upper limit.

#define BUILD0(x) x[0]
#define BUILD1(x) BUILD0(x), x[1]
#define BUILD2(x) BUILD1(x), x[2]
#define BUILD3(x) BUILD2(x), x[3]
#define BUILD(x, i) BUILD##i(x)

And note that i should be an integer literal, not a constant computed value.

BTW, the preprocessor is more powerful than what is usually though, but the use of that power is quite tricky. Boost provides a library which eases some things, including iteration. See Boost Preprocessor Library. There is another library for such things, but its name escapes me at the moment.

Edit: The boost preprocessor library uses a similar technique. With additional tricks to solve some corner cases problems, share implementation macros between higher level facilities, work around compiler bugs, etc... the usual boost complexity which is normal in the context of a general purpose library but which at times prevents easy understanding of the implementation principles. Probably the most noticeable trick is to add an indirection level so that if the second parameter can be a macro, it is expanded. I.e. with

#define BUILD_(x, i) BUILD##i(x)
#define BUILD(x, i) BUILD_(x, i)

one can make the call

#define FOO 42
BUILD(x, FOO)

which isn't possible with what I exposed.

Jens
  • 69,818
  • 15
  • 125
  • 179
AProgrammer
  • 51,233
  • 8
  • 91
  • 143
3

No, it isn't - macros cannot be recursive. And the macros you posted are not variadic, which means "having different numbers of parameters".

0

Ok, I had the same problem, My aim was to print all the values of an array of N bytes using macros. I assume you had pretty much the same problem. If this was the case, this solution should suit future similar problems.

#define HEX_ARRAY_AS_STR(array, len) \
    ({ \
        int print_counter = 0; \
        print_buf = calloc(len*3+1, 1); \
        char *tmp_print_buf = print_buf; \
        uint8_t *array_flower = array;  \
        while(print_counter++ < (len)){ \
            sprintf(tmp_print_buf, "%02X ", *(array_flower)++); \
            tmp_print_buf += 3; \
        } \
        print_buf; \
    })

#define eprintf(...) \
    do{ \
        char *print_buf; \
        printf(__VA_ARGS__); \
        if(print_buf) \
            free(print_buf); \
    }while(0)

int 
main(int argc, char *argv[])
{
    uint8_t sample[] = {0,1,2,3,4,5,6,7};
    eprintf("%s\n", HEX_ARRAY_AS_STR(sample, 8));
    return 0; 
}
  • No, this isn't what I was trying to do. Anyway, if you always pass an array to HEX_ARRAY_AS_STR you could get rid of the second parameter by using sizeof(array)/sizeof(uint8_t) – Giovanni Funchal Oct 27 '11 at 13:39