C preprocessor using the closing bracket of a parent macro

北战南征 提交于 2019-12-05 06:31:08

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.

  • Using this tool makes it clear that in Expansion#2 (third image) we have an unterminated set of brackets, thus locating the error.

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") );

This is about the order in which the macros are processed. The simplest solution is to add additional parentheses around the Z argument.

    printf( Z( (A("1")("2") "3")) );
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!