Home > Enterprise >  Nested invocations of function-like macros
Nested invocations of function-like macros

Time:10-05

Consider the following code snippet:

#define FOO() BAR
#define BAR() FOO

FOO()()()

The C standard tells us that after argument substitution etc., the preprocessing tokens resulting from a macro invocation are re-scanned for further macro-names, ignoring the name of the macro that generated them (c99, 6.10.3.4p1-2)

Thus, I'd expect the preprocessor to turn the snippet into BAR()(), then FOO(), and then stop, because the token FOO is a result of the macro FOO, and isn't recognized as a macro name.

But both GCC and clang give me the result BAR, indicating that it is, in fact, expanding one more time. This makes sense only if the invocation of the macro "happens" at the argument list - where the macro name FOO is no longer ignored - and not at the macro name itself. This is very unintuitive, and I find no mention of it in the standard. What am I missing?

Thanks in advance!

CodePudding user response:

Here is the relevant passage from the C Standard:

6.10.3.4 Rescanning and further replacement

1 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.

2 If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file’s preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.

3 The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one, but all pragma unary operator expressions within it are then processed as specified in 6.10.9 below.

If for example you had written

#define QQ() QQ
QQ()()()

The expansion would be just QQ()() because as per 2) when QQ is found during the scan of the replacement list, it is not expanded.

Conversely, in your example, FOO is not found in the replacement list of FOO(), BAR is followed by () which causes it to be expanded and in turn BAR not found in the replacement list of BAR(), but FOO followed by the last set of () is again expanded.

The phrase if any nested replacements encounter the name of the macro being replaced, it is not replaced refers to replacements occurring during expansion of macro arguments. In your example, the replacements occur iteratively, not recursively, hence extra set of () will cause further expansion.

  • Related