Question Details

No question body available.

Tags

c c-preprocessor defer-keyword disabling-context

Answers (2)

January 16, 2026 Score: 3 Rep: 127,601 Quality: Medium Completeness: 60%

The whole thing about "marking" and "disabling" is irrelevant to this case. All that matters here is the rule about rescanning the result of a macro expansion to look for further expansions. When that happens, it looks ONLY at the resulting body and following tokens. It DOES NOT look back at preceding tokens to see if any of them are now macros.

So after expanding DEFER the "resulting body and following tokens" is:

X1 = A EMPTY() ()
     ^
   scanning point

Here it sees A does not match a macro, because the next token is not (. So it says it is finished with the token A. It then looks at EMPTY() and sees a macro to expand and then rescan. After expanding that, it has

X1 = A   ()
       ^
     scanning point

It DOES NOT back up at this point, it just keeps scanning with the (empty) body it just substituted and does not see any further macros to expand.

November 2, 2025 Score: 0 Rep: 146,309 Quality: Medium Completeness: 80%

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 ().