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 with 4
, so it is as if xstr(4)
had been used.
- In the replacement text
str(s)
, the parameter s
is replaced with 4
, producing str(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.