11

I have a general macro:

#define mSwitch( Root, Case )  Root##_Case_##Case

#define mSpecialDisplay( what, Val )  mSwitch(mSpecialDisplay,what)(Val)
#define mSpecialDisplay_Case_Int(Val)    ...do stuff
#define mSpecialDisplay_Case_Float(Val)  ...do stuff
...more special cases

how do I guarantee that the variable Case is fully expanded before it gets pasted in mSwitch?

It works fine if mSwitch is passed a literal value, but if there are several layers of indirection, or intermediary operations, mSwitch ends up pasting one of those before they get fully expanded.

I'm using MSVC 2005.

Is there a simple way to make sure a parameter is fully expanded before pasting is done?

Thanks


well, it isn't that hard to give an example maybe:

  #define mMDebugInfo( ... ) mMDebugExp( mMDebugInfo_( 0, __VA_ARGS__ ) )

  #define mMDebugInfo_( C, ... ) mMAritize( mMSwitch( mMDebugInfo, mMMetaTrait( Detect, __VA_ARGS__ ) ), (C, __VA_ARGS__) )

  #define mMDebugInfoRep( C, ... ) mMXP##C( mMDebugInfo_ )mMXP##C((mMIInc(C),__VA_ARGS__)) //(mMExpDo(mMGlue( mM, C)##DebugInfo_(mMIInc(C),__VA_ARGS__))

  #define mMDebugInfo1( C, ... ) mMAritize( mMSwitch( mMDebugInfo, mMMetaTrait( Detect, __VA_ARGS__ ) ), (mMIInc(C), __VA_ARGS__) )

  #define mMDebugInfo_Case_Nil(...) [Nil]

  #define mMDebugInfo_Case_CntArgs(C,I,...) 
mMDebugInfoRep(C,I),mMDebugInfoRep(C,__VA_ARGS__)
  #define mMDebugInfo_Case_PrnNull(C,I) [()]

  #define mMDebugInfo_Case_Prn(C,I)   ( mMDebugInfoRep(C,mMDPrn(I)) )

  #define mMDebugInfo_Case_ActFn(C,I) mMAritize( mMDebugInfo_Case_Fn, (C, I, mMTrait_Fn_mM##I) )

  #define mMDebugInfo_Case_PassFn(C,I) mMAritize( mMDebugInfo_Case_Fn, (C, mMTrait_Fn_mM##I) )

  #define mMDebugInfo_Case_Fn( C,Name, Reg, ArgCnt, PArgs ) [Name:ArgCnt]( mMAritize( mMSwitch( mMDebugInfo_Case_Fn, ArgCnt ), (C, mMDPrn( PArgs ) )) )

  #define mMDebugInfo_Case_Fn_Case_V(C, _1, ...) mMDebugInfoRep(C, _1), mMDebugInfoRep(C, __VA_ARGS__)

  #define mMDebugInfo_Case_Fn_Case_0(...) [Nil]

  #define mMDebugInfo_Case_Fn_Case_1(C, _1, ...) mMDebugInfoRep(C, _1)

  #define mMDebugInfo_Case_Fn_Case_2(C, _1, _2, ...) mMDebugInfoRep(C, _1), mMDebugInfoRep(C, _2)

  #define mMDebugInfo_Case_Fn_Case_3(C, _1, _2, _3, ...) mMDebugInfoRep(C, _1), mMDebugInfoRep(C, _2), mMDebugInfoRep(C, _3)  

  #define mMDebugInfo_Case_Fn_Case_4(C, _1, _2, _3, _4, ...) mMDebugInfoRep(C, _1), mMDebugInfoRep(C, _2), mMDebugInfoRep(C, _3), mMDebugInfoRep(C, _4)

  #define mMDebugInfo_Case_Int(C,I)   [Num:I]

  #define mMDebugInfo_Case_Digit(C,I) [Dig:I] 

  #define mMDebugInfo_Case_Bool(C,I)  [Bin:I]

  #define mMDebugInfo_Case_CCode(C,I) [CCd:I]

  #define mMDebugInfo_Case_UToken(C,I) [UT:I]

this is debug code that has no problems recursively parsing nested expressions like:

DebugInfo( BInt( BNot( IAdd(4,BNot(IAdd(6,7)) ) ) ) ); 
"

which yields:

"[BInt:1]( [BNot:1]( [IAdd:2]( [Dig:4], [BNot:1]( [IAdd:2]( [Dig:6], [Dig:7] ) ) ) ) )"

The macro functions in the example expression are in inactive form. The problem is happening when I activate the form - the parse chain for the individual arguments can get arbitrarily long and they aren't getting resolved completely before they are getting used.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Anephezeton
  • 305
  • 1
  • 3
  • 8

1 Answers1

18

This is the usual idiom for this:

#define mSwitch(Root, Case) mSwitch_(Root, Case)
#define mSwitch_(Root, Case) Root##_Case_##Case

All of the arguments to a C preprocessor macro are fully expanded before the macro itself is expanded, unless the # or ## operator is applied to them; then they're not expanded. So to get full expansion before ##, you pass the arguments through a wrapper macro that doesn't use ##.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • 4
    Unrelatedly, out of morbid curiosity, where do people learn to write "`function( argument, argument )`" -- i.e. with spaces inside the parentheses? I see it fairly often and it makes my sense of aesthetics writhe in pain. – zwol Jul 11 '10 at 05:00
  • thanks, I tried that. I think the problem is getting exteneded because the intermediary operations may be applying pastes of their own. If I create an arbitrarily long enough list of: #define mSwitch( A, B ) mSwitch1(A,B) #define mSwitch1( A, B ) mSwitch2(A,B) ... #define mSwitchN( A, B ) Root##_Case_##Case it eventually works. Is there anything else to try? – Anephezeton Jul 11 '10 at 05:04
  • @Zack, it's required style in some places (like the one I work in). You'll get used to it. – JSBձոգչ Jul 11 '10 at 05:13
  • There's no other way to control whether or not this happens, but one level of wrapper *should* be enough regardless of what else is going on. I would need to see a complete self-contained example where things go wrong, to give more specific advice. (It's quite possible that you've hit an MSVC bug, by the way. Have you tried the 2008 edition? Or gcc?) – zwol Jul 11 '10 at 05:13
  • 1
    @JS Bangs, I know a lot of places have that in their required style guide (thankfully *not* where I work) but where does it *come* from? Who invented it? – zwol Jul 11 '10 at 05:15
  • yeah, zack, I think it is a bug. I can't really give a concise example because the problem is actually occurring in preprocessor library I am writing that allows fully recursive macro definitions. The pasting problem is happening when I am parsing the arguments of a macro Fn and the additional stuff that needs to get resolved is the macros that perform the actual parsing on the argument before I activate it. – Anephezeton Jul 11 '10 at 05:22
  • I'm betting bug, yes, but your longer example doesn't help me. I can't figure out what's going on from a bunch of `#define`s and then some apparently-unrelated function calls. I need a complete, self-contained thing I can paste into a .c file and feed to various compilers and see what happens. Ideally also you would provide the result of preprocessing with MSVC 2005, which I cannot conveniently test. – zwol Jul 11 '10 at 06:48
  • hmmm, well, if the standard says passing arguments through one level of indirection (that has no pasting in it itself) should result in complete expansion, then it is a bug. It definitely does not resolve completely. I'll have to look for a work-around. It appears to require one level of indirection for EACH expansion that involves a paste operation. – Anephezeton Jul 11 '10 at 07:00
  • "It appears to require one level of indirection for EACH expansion that involves a paste operation" -- yeah, that's a bug. The way the standard puts it is a bit more complicated than "should result in complete expansion", but yes, it's supposed to repeatedly expand the contents of macro arguments till it can't expand them any more and only then substitute that text into the expansion of the macro proper. – zwol Jul 11 '10 at 07:12
  • Thanks, zack, thats what I thought too, and it would sure make my life easier if it worked that way. – Anephezeton Jul 11 '10 at 07:17