Reputation: 51
I have a question about '##' for pre-processor pasting with a dereference operator. Could anyone tell me why the code below will not compile?
typedef struct
{
char data;
} MY_STRUCT;
MY_STRUCT My_Instance;
MY_STRUCT* My_PInstance;
#if 1
#define GET_MEMBER(membername) (My_PInstance->##membername)
#else
#define GET_MEMBER(membername) (My_Instance.##membername)
#endif
Then later when I call:
char value = GET_MEMBER(data); // Where My_PInstance is properly instantiated.
I get a compile error.
error: pasting "->" and "data" does not give a valid preprocessing token
Upvotes: 3
Views: 1771
Reputation: 476
Just for anybody else who comes this way. I had the same problem, but with the '.' variant of the GET_MEMBER(..) macro that wasn't discussed, but I think the problem is the same.
I accepted cwyang's answer hesitantly, as what was really getting pasted was the text
My_PInstance->
with
data
With -- per my (and user...'s) thinking -- the result being a proper token.
My_PInstance->data
So, I persisted through more google results. Eventually I came to this guy, who gives a historical note that was a real blow. Summary:
Man. This guy says there's no hope....
Well, what the heck? I went there. The alternative syntax worked, and I'm hardly using an ancient compiler!
g++ (GCC) 4.7.3
Copyright (C) 2012 Free Software Foundation, Inc.
So, for all you intrepid stringifiers and concatenators and tokenizers (!) out there, here is my lesson for you.
Before:
#define PROFILING_START_CLK(STAT, n) \
time0##STAT##n = PRF_CLK_FN(); \
profilingStatsIndex##STAT##n = STAT##.count % PROFILE_SIZE; \
STAT#.count++;
called thus:
PROFILING_START_CLK(tst, 0);
Returns 2 intances of the following error for each place it was used:
error: pasting "tst" and "." does not give a valid preprocessing token
Just like user1159503.
Moving on, though.... The following works:
#define PROFILING_START_CLK(STAT, n) \
time0##STAT##n = PRF_CLK_FN(); \
profilingStatsIndex##STAT##n = STAT/**/.count % PROFILE_SIZE;\
---------------------------------------^^^^
STAT/**/.count++;
--------^^^^
The before/after versions worked failed/compiled, whether I used the g++ -ansi switch or not.
The reason it works is because the preprocessor strips comments before getting into macros, so the order is something like this.
Should '##' work to assemble arbitrary structs &/or members in a macro? I don't know. I would think so, but it also seems correct for the pasting process to not span operators.
Otherwise, the question would be, "Is it reasonable for pasting process to span only "joining" operators like we're talking about here. ('.', '->', '::', ....)"
Upvotes: 2
Reputation: 1243
You need not paste.
Just do (My_Pinstance->membername)
'##' should paste two tokens into one valid token. However
->foo
is not valid token. (foo is for example)
Upvotes: 6