1

This snippet is mostly from the Cloak wiki, C Preprocessor tricks, tips and idioms, with DEFER2, X1, and X2 added by me for ease of referencing things in this post.

#define EMPTY()
#define DEFER(id)  id EMPTY()
#define DEFER2(id) id
#define A()        123

X1 = DEFER(A)()   // Expands to A () because it requires one more scan to fully expand
X2 = DEFER2(A)()

Result of preprocessing:

X1 = A ()
X2 = 123

The explanation given in the same wiki is,

...when a macro is scanned and expanding, it creates a disabling context. This disabling context will cause a token, that refers to the currently expanding macro, to be painted blue. Thus, once its painted blue, the macro will no longer expand. This is why macros don't expand recursively. However, a disabling context only exists during one scan, so by deferring an expansion we can prevent our macros from becoming painted blue.

I'm unable to understand why EMPTY() in the body of DEFER should result in any deferring.

DEFER(A)()
// A EMPTY()()
// A ()        <--- the preprocessor stops here, for some reason!
// 123

If A() would expand to 123 in the DEFER2 case, why should the preprocessor stop expanding A () in the DEFER case? Why is A considered part of the disabling context in case of DEFER but not in that of DEFER2?

I have also consulted the The C Preprocessor GNU reference, section Macro Pitfalls but still no clue.

1 Answer 1

0

The () after the macro are not part of the macro.

DEFER(A)()
        ^^ - some by standing quotes doing nothing
^^^^^^^^   - the actual macro

The "rescanning" of the macro joins the macro result with all other subsequent text, so it may "pick up" the following ().

why should the preprocessor stop expanding A () in the DEFER case?

The DEFER(A) does not "pick up" the () followed by it, because it picks up EMPTY() during rescanning.

DEFER(A)()
^^^^^^^^      - expanding this
A EMPTY() ()
^^^^^^^^^^^^  - rescanning (once). EMPTY() is replaced.
A ()          - result

In contrast:

DEFER2(A)()
^^^^^^^^^    - expanding this
A ()
^^^^         - rescanning result and following tokens
123

The rule is in https://port70.net/~nsz/c/c11/n1570.html#6.10.3.4p1 :

After all parameters in the replacement list have been substituted and # and ## processing has taken place, all placemarker preprocessing tokens are removed. The resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.

Why is A considered part of the disabling context in case of DEFER but not in that of DEFER2?

I would say A() is not really disabled, rather everything after EMPTY() becomes disabled (not part of the macro), so A does not join with ().

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the link, I'll have to study it carefully, which will take me some time -- grokking any language standard/specification takes time. Meanwhile, I'd love to be able to quickly understand why the CPP stops after A () in the DEFER(A)() case, unlike the DEFER2(A)() case. Note that I trivially agree with your opening remark -- "The () after the macro are not part of the macro" -- but why doesn't it apply equally to both cases? Also, is the whole file rescanned for macro expansions, or only macro invocation portion? What are the begin-end extents of the disabling context? Etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.