The relevant steps of macro expansion are (per C 2011 [n1570] 6.10.3.1 and C++ 1998 16.3.1):
- Process tokens that are preceded by
#
or##
. - Apply macro replacement to each argument.
- Replace each parameter with the corresponding result of the above macro replacement.
- Rescan for more macros.
Thus, with xstr(foo)
, we have:
- The replacement text,
str(s)
, contains no#
or##
, so nothing happens. - The argument
foo
is replaced with4
, so it is as ifxstr(4)
had been used. - In the replacement text
str(s)
, the parameters
is replaced with4
, producingstr(4)
. str(4)
is rescanned. (The resulting steps produce”4”
.)
Note that the problem with str(foo)
is that step 2, which would replace foo
with 4
, comes after step 1, which changes the argument to a string. In step 1, foo
is still foo
; it has not been replaced with 4
, so the result is ”foo”
.
This is why a helper macro is used. It allows us to get a step 2 performed, then use another macro to perform step 1.