Daniel Walker
Daniel Walker

Reputation: 6740

C preprocessor macro expanding itself

I believe that the answer to my question is tied to C Preprocessor, Stringify the result of a macro. However, I'm having trouble applying the solution to my use case.

I have this function:

astNodePtr createNode(int lineno, int nodeType, ...);

I have this macro which goes along with it:

#define NODE(nodeType, ...) createNode(yylineno,nodeType,##__VA_ARGS__)

All works fine until I get to a line like this:

NODE(1,x,NODE(2,y,z))

My linker gives me an error: undefined reference to 'NODE'

EDIT:

I've tried (inspired by the fore-mentioned link)

#define EXPAND(x) ##x
#define NODE(nodeType, ...) createNode(yylineno,nodeType, EXPAND(__VA_ARGS__))

However, I got the same error.

EDIT:

I should mention that I also use the macro thus: NODE(5)

Therefore, I need the ## in front of __VA_ARGS__ in order to avoid the trailing comma problem.

Upvotes: 1

Views: 264

Answers (2)

Tom Karzes
Tom Karzes

Reputation: 24052

Get rid of the ## in the macro body. That's blocking the expansion of the nested call. I.e. try:

#define NODE(nodeType, ...) createNode(yylineno,nodeType,__VA_ARGS__)

Update: With the edit to your question, I now understand the need for the ## in your macro. Chris Dodd's solution solves this problem nicely.

Here is another way to do it. This solution adds a layer of expansion which handles the nested macros at the top level, then addresses the trailing comma problem at the lower level:

#define NODE2(nodeType, ...) createNode(yylineno,nodeType,##__VA_ARGS__)
#define NODE(...) NODE2(__VA_ARGS__)

This handles the following sample cases as desired, with no trailing comma:

NODE(a,NODE(b,c))
NODE(x)
NODE(NODE(y))

The advantage to this approach is that it is slightly more general. In particular, it will work even if there is no mandatory nodeType argument. For example, if the name is changed to FOO and the nodeType argument is eliminated, the following will work:

#define FOO2(...) createNode(yylineno,##__VA_ARGS__)
#define FOO(...) FOO2(__VA_ARGS__)

This handles the following sample cases, with no trailing comma:

FOO(FOO(b))
FOO()
FOO(FOO())

Upvotes: 4

Chris Dodd
Chris Dodd

Reputation: 126203

You actually just need

#define NODE(...) createNode(yylineno, __VA_ARGS__)

The problem is that using ## also prevents the expansion of macros in the __VA_ARGS__ argument prior to substitution, and, while macros can be exapanded after substitution, they can't be expanded recursively, so if you want to have a NODE macro in an argument to another NODE macro, you can't use ##. Fortunately in your case, you can avoit the need for ## to get rid of the trailing comma in NODE calls with no extra arguments (which is a non-standard gcc extension anyways) by always having at least one argument for the ... -- the nodeType argument.

Upvotes: 2

Related Questions