cpp: Stringizing

1 
1 3.4 Stringizing
1 ===============
1 
1 Sometimes you may want to convert a macro argument into a string
1 constant.  Parameters are not replaced inside string constants, but you
1 can use the '#' preprocessing operator instead.  When a macro parameter
1 is used with a leading '#', the preprocessor replaces it with the
1 literal text of the actual argument, converted to a string constant.
1 Unlike normal parameter replacement, the argument is not macro-expanded
1 first.  This is called "stringizing".
1 
1    There is no way to combine an argument with surrounding text and
1 stringize it all together.  Instead, you can write a series of adjacent
1 string constants and stringized arguments.  The preprocessor replaces
1 the stringized arguments with string constants.  The C compiler then
1 combines all the adjacent string constants into one long string.
1 
1    Here is an example of a macro definition that uses stringizing:
1 
1      #define WARN_IF(EXP) \
1      do { if (EXP) \
1              fprintf (stderr, "Warning: " #EXP "\n"); } \
1      while (0)
1      WARN_IF (x == 0);
1           ==> do { if (x == 0)
1                 fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0);
1 
1 The argument for 'EXP' is substituted once, as-is, into the 'if'
1 statement, and once, stringized, into the argument to 'fprintf'.  If 'x'
1 were a macro, it would be expanded in the 'if' statement, but not in the
1 string.
1 
1    The 'do' and 'while (0)' are a kludge to make it possible to write
1 'WARN_IF (ARG);', which the resemblance of 'WARN_IF' to a function would
1 make C programmers want to do; see ⇒Swallowing the Semicolon.
1 
1    Stringizing in C involves more than putting double-quote characters
1 around the fragment.  The preprocessor backslash-escapes the quotes
1 surrounding embedded string constants, and all backslashes within string
1 and character constants, in order to get a valid C string constant with
1 the proper contents.  Thus, stringizing 'p = "foo\n";' results in
1 "p = \"foo\\n\";".  However, backslashes that are not inside string or
1 character constants are not duplicated: '\n' by itself stringizes to
1 "\n".
1 
1    All leading and trailing whitespace in text being stringized is
1 ignored.  Any sequence of whitespace in the middle of the text is
1 converted to a single space in the stringized result.  Comments are
1 replaced by whitespace long before stringizing happens, so they never
1 appear in stringized text.
1 
1    There is no way to convert a macro argument into a character
1 constant.
1 
1    If you want to stringize the result of expansion of a macro argument,
1 you have to use two levels of macros.
1 
1      #define xstr(s) str(s)
1      #define str(s) #s
1      #define foo 4
1      str (foo)
1           ==> "foo"
1      xstr (foo)
1           ==> xstr (4)
1           ==> str (4)
1           ==> "4"
1 
1    's' is stringized when it is used in 'str', so it is not
1 macro-expanded first.  But 's' is an ordinary argument to 'xstr', so it
11 is completely macro-expanded before 'xstr' itself is expanded (⇒
 Argument Prescan).  Therefore, by the time 'str' gets to its argument,
1 it has already been macro-expanded.
1