views:

158

answers:

3

Hi,

I've distilled my problem down to this code snippet - but it is a part of a larger program so I don't want a different way to do this - I need a way to make this work!

When I generate a preprocessed file from this code:

#define OUTER(a, b) \
    a##b
#define INNER(c, d) \
    c##d

enum foo {
    OUTER(INNER(x, y), z)
}; // line 108

int APIENTRY _tWinMain(...)
{
    foo bar = xyz; // line 112
}

I get:

enum foo {
    xyz
}; // line 108

int __stdcall wWinMain(...)
{
    foo bar = xyz; // line 112
}

which is what I want. However, if I try to compile the code I get:

error C2146: syntax error : missing '}' before identifier 'z' line 108
error C2143: syntax error : missing ';' before '}' line 108
error C2143: syntax error : missing ';' before '}' line 108
error C2059: syntax error : '}' line 108
error C2065: 'xyz' : undeclared identifier line 112

I can't work it out! The problem seems to be caused by the ## in the:

#define OUTER(a, b) \
    a##b

but why (and how to fix it) is beyond me...

+9  A: 

Use this instead:

#define CONCAT(X,Y) X##Y
#define OUTER(a, b) CONCAT(a,b)
#define INNER(a, b) CONCAT(a,b)

enum foo {
    OUTER(INNER(x, y),z)
}; // line 108

int main(...)
{
    foo bar = xyz; // line 112
}
Luther Blissett
Woo hoo it works! But can you explain to me why it works? Why is my preprocessed output correct? I see from the gcc error described below that it appears to be keeping a ")" and trying to concatenate the "z" to "xy)"? But this doesn't appear in my preprocessed output!
Jack
Read Jonathan Leffler's canonical answer:http://stackoverflow.com/questions/1489932/c-preprocessor-and-concatenation
Luther Blissett
Ah! Is OUTER getting "INNER(c, d), z" and not "xy, z" as I thought? That would make sense. But I still don't get why my preprocessed output is correct!
Jack
No need to declare two separate OUTER/INNER macros, this works also:OUTER(OUTER(x, y),z)
0x69
+1  A: 

If you are using gcc, then you can give it the -E option to see the preprocessed output. Then you can easily see what the preprocessor has output and how to further debug your macros. Other compilers also have similar options.

zvrba
+2  A: 

Preprocessing your example with gcc results in:

enum foo {
t.c:7:1: error: pasting ")" and "z" does not give a valid preprocessing token
    xy z
};

which should give you a clue of why Luther's solution works and yours doesn't.

Employed Russian