Stringification - how does it work?
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.
First case
- Evaluate
str(foo)
: Substitutestr(foo)
with#foo
, ie"foo"
Second case
- Evaluate
xstr(foo)
: Substitutexstr(foo)
withstr(<foo-value>)
, iestr(4)
- Evaluate
str(4)
: Substitutestr(4)
with#4
, ie"4"
Generally,
preprocessor evaluates macro-functions expanding macro-variables, until it is nothing to evaluate:
If you define
#define xstr(s) str(s) + 1
#define str(s) s + 1
in the following code
#define foo 4
int main()
{
std::cout << str(foo) << '\n'
<< xstr(foo) << '\n' ;
}
it would evaluate like
First string
- Substitute
str(foo)
with<foo-value> + 1
, ie4 + 1
- Nothing more to substitute. Finishing.
And result is 4 + 1
Second string
- Substitute
xstr(foo)
withstr(<foo-value>) + 1
, iestr(4) + 1
- Substitute
str(4)
with<4-value> + 1
, ie4 + 1
- Nothing more to substitute.
And result is 4 + 1 + 1