I have this code which works:
#include <stdio.h>
#define A(x) x B
#define B(x) C(x,
#define C(x,y) y x)
int main( void ) {
printf( A("1") ("2") "3" );
}
It prints 132
(the point of the A
macro is to swap the thing which follows its parameters in brackets with everything after that until another closing bracket)
But if I use that within another macro:
#define Z(x) x
printf( Z( A("1") ("2") "3" ) );
I get the compile error "Unterminated function-like macro invocation".
I realise that this happens because the compiler is trying to process the arguments of Z
independently, but I need to use its closing bracket as a marker. Is there a way I can make this work within macros? Changing the calling syntax isn't really an option.
p.s. Before I get any responses talking about what an awful thing this is to do, rest assured: this is not for real code. It is a problem which came up while making a toy program which uses define
to simulate a new language inside C.
The easiest way to see what's going on is to change the test case a little.
#define A(x) x B
#define B(x) C(x,
#define C(x,y) y x] /* note close square bracket instead of close paren */
Y(A(1)(2)3)
preprocesses to Y(1 3 2]
. This is because an intermediate stage of expansion looked like
Y(1 C(2,3)
at which point C
ate the close paren that appeared to belong to Y
in the original text and replaced it with a close bracket.
Now, what happens differently if A(1)(2)3
is inside a macro argument?
#define Z(x) x
Z(A(1)(2)3)
Because of argument prescan, the analogous intermediate stage of expansion is not
Z(1 C(2,3)
but rather
1 C(2,3
with Z
squirrelled away on a hidden "pending expansions" stack. The preprocessor is, in effect, enforcing the textual appearance that that final close paren belongs to Z
, and C
is not allowed to borrow it.
The least-invasive way I can think of to achieve your original goal is
#define _A(x) x B
#define B(x) C(x,
#define C(x,y) y x)
#define Z(x) ZZ((_##x))
#define ZZ(x) ZZZ x
#define ZZZ(x) [x]
Z(A(1)(2)3)
preprocesses to [1 3 2]
. We use the token paste operator to prevent Z
's argument from being prescanned, so we can add a temporary extra set of parentheses for use by C
. ZZ
and ZZZ
then strip them off again. The catch is that it's an error if you don't paste x
with something, so we have to add a leading underscore to the definition of A
, and it will be an error if the first token of Z
's argument is ever not something that can be token-pasted after an underscore.
You might want to consider using M4 instead of trying to shoehorn this into the C preprocessor.
eclipse cdt is excellent to debug your questions. for eclipse, just hover over a macro to get started. here is detialed info on it:
C/C++ Software Development with Eclipse >> 2.1.7. Macro Expansion
for your second macro, eclipse shows the following:
int main (void) {
printf( Z( A("1") ("2") "3" ) );
}
Spotting the Error
Notice in the expansion #3 C("2", "3" just 'disappears. I take this as CDT's way of saying 'unterminated argument list'. Whatever the case for it disappearing, this is the method I prefer to take when debugging macros.
Understanding a Solution
After fiddling around a bit using this tool, I think this is what you were after:
printf( Z( (A("1") ("2") "3") ) );
yields (using gcc -E main.c -c)
printf( ("1" "3" "2") );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With