16.3.2 The # operator [cpp.stringize]
1 Each # preprocessing token in the replacement list for a function-like macro shall be followed by a parameter
immediately preceded by a # preprocessing token, both are replaced by a single character string literal
preprocessing token that contains the spelling of the preprocessing token sequence for the corresponding
argument. Each occurrence of white space between the argument’s preprocessing tokens becomes a single
space character in the character string literal. White space before the first preprocessing token and after
the last preprocessing token comprising the argument is deleted. Otherwise, the original spelling of each
preprocessing token in the argument is retained in the character string literal, except for special handling
for producing the spelling of string literals and character literals: a \ character is inserted before each " and
\ character of a character literal or string literal (including the delimiting " characters). If the replacement
that results is not a valid character string literal, the behavior is undefined. The character string literal
1 A ## preprocessing token shall not occur at the beginning or at the end of a replacement list for either form
of macro definition.
2 If, in the replacement list of a function-like macro, a parameter is immediately preceded or followed by
a ## preprocessing token, the parameter is replaced by the corresponding argument’s preprocessing token
sequence; however, if an argument consists of no preprocessing tokens, the parameter is replaced by a
placemarker preprocessing token instead.156
3 For both object-like and function-like macro invocations, before the replacement list is reexamined for more
macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an
argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing
token. Placemarker preprocessing tokens are handled specially: concatenation of two placemarkers results
in a single placemarker preprocessing token, and concatenation of a placemarker with a non-placemarker
preprocessing token results in the non-placemarker preprocessing token. If the result is not a valid preprocessing
token, the behavior is undefined. The resulting token is available for further macro replacement.
The order of evaluation of ## operators is unspecified.
#define mkstr(a) # a
#define in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
char p[] = join(x, y); // equivalent to
// char p[] = "x ## y";
1 Each # preprocessing token in the replacement list for a function-like macro shall be followed by a parameter
as the next preprocessing token in the replacement list.
immediately preceded by a # preprocessing token, both are replaced by a single character string literal
preprocessing token that contains the spelling of the preprocessing token sequence for the corresponding
argument. Each occurrence of white space between the argument’s preprocessing tokens becomes a single
space character in the character string literal. White space before the first preprocessing token and after
the last preprocessing token comprising the argument is deleted. Otherwise, the original spelling of each
preprocessing token in the argument is retained in the character string literal, except for special handling
for producing the spelling of string literals and character literals: a \ character is inserted before each " and
\ character of a character literal or string literal (including the delimiting " characters). If the replacement
that results is not a valid character string literal, the behavior is undefined. The character string literal
corresponding to an empty argument is "". The order of evaluation of # and ## operators is unspecified.
1 A ## preprocessing token shall not occur at the beginning or at the end of a replacement list for either form
of macro definition.
2 If, in the replacement list of a function-like macro, a parameter is immediately preceded or followed by
a ## preprocessing token, the parameter is replaced by the corresponding argument’s preprocessing token
sequence; however, if an argument consists of no preprocessing tokens, the parameter is replaced by a
placemarker preprocessing token instead.156
3 For both object-like and function-like macro invocations, before the replacement list is reexamined for more
macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an
argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing
token. Placemarker preprocessing tokens are handled specially: concatenation of two placemarkers results
in a single placemarker preprocessing token, and concatenation of a placemarker with a non-placemarker
preprocessing token results in the non-placemarker preprocessing token. If the result is not a valid preprocessing
token, the behavior is undefined. The resulting token is available for further macro replacement.
The order of evaluation of ## operators is unspecified.
[ Example: In the following fragment:
#define hash_hash # ## ##define mkstr(a) # a
#define in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
char p[] = join(x, y); // equivalent to
// char p[] = "x ## y";