Simon Parker
Simon Parker

Reputation: 1834

Dropping the last comma in a macro

I am using the X macro pattern to keep a bunch of arrays/items in sync, and I want to create an argument list from it, however I can't work out a way to get a well formed list. Here's what I mean:

#define MY_DATA \
    X(var_one, e_one, 1) \
    X(var_two, e_two, 2) \
    X(var_three, e_three, 3) \

#define X(a,b,c) b,
enum MyNumbers {
    MY_DATA
};
#undef X

#define X(a,b,c) c,
int MyValues[] = {
    MY_DATA
};
#undef X

void my_func(int a, int b, int c) {} // example do-nothing proc

void main(void)
{
    int var_one = MyValues[e_one];
    int var_two = MyValues[e_two];
    int var_three = MyValues[e_three];

#define X(a,b,c) a,

    my_func(MY_DATA);  // this fails because of the trailing comma

#undef X
}

Macros are not really my forte, so I can't think of a way of getting rid of the final comma in the function call. Can anyone think of a way to stop it?

Upvotes: 0

Views: 517

Answers (3)

user3344003
user3344003

Reputation: 21637

I use a variant of this pattern frequently. However, it is normally used to define mappings between data. Along the lines of this:

MESSAGE(10, "Some error message"),
MESSAGE(11, "Som other error message"),

What des not make sense in your approach is that typically these constructs are used for large numbers of entries (100s, 1000s). You normally do not want that many arguments to a function.

If you really want to follow the approach, you could add another MACRO

#define MY_DATA \ X(var_one, e_one, 1) COMMA \ X(var_two, e_two, 2) COMMA \ X(var_three, e_three, 3) \

and define comma as needed when you define X. (Or you could just put the comma in directly).

Upvotes: 1

M.M
M.M

Reputation: 141628

Here is an option:

void my_func(int a, int b, int c, int dummy) {}

// ...

my_func(MY_DATA 0);

If you can't change my_func then make a thunk (i.e. an intermediate function that calls my_func)

A second option would be to include the comma in the MY_DATA macro instead of in X:

#define MY_DATA \
  X(var_one, e_one, 1), \
  X(var_two, e_two, 2), \
  X(var_three, e_three, 3)

Upvotes: 0

JDługosz
JDługosz

Reputation: 5652

Look at the Boost Preprocessor library for “preprocessor metaprogramming tools including repetition and recursion.”

Even if you don't use their complete package, the chapter I linked to explains some techniques, specifically including iteration to build data structures and statements.

Here's an idea: write

my_func(MY_DATA 0);

and declare my_func to take an extra (ignored) argument.

void my_func(int a, int b, int c, int)

Upvotes: 2

Related Questions