Issue 1084: Unspecified evaluation order of # and ##

Authors: Jay Ghiron
Date: 2026-06-19
Submitted against: C23
Status: Open

The order of evaluation of # and ## operators is unspecified.

(C23 6.10.5.3 "The # operator" paragraph 4.)

This intends to make the following unspecified:

#define F(X,Y)X###Y

However, the way this works if ## is evaluated first is unclear. For the following questions assume that F and the following macro are always defined:

#define S(...)#__VA_OPT__(__VA_ARGS__)

Question 1

S(F(,0))

If # is evaluated first the result is clear, a placemarker preprocessing token is concatenated with "0" which results in "0" so stringizing that results in "\"0\"". If the ## is evaluated first then the placemarker preprocessing token is concatenated with a # punctuator preprocessing token producing a # punctuator preprocessing token. However, since the parameter Y was preceded by a # punctuator preprocessing token in the replacement-list it will not be expanded as usual and will instead be subject to stringization:

If, in the replacement list, a parameter is 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 (excluding placemarker tokens).

(C23 6.10.5.3 "The # operator" paragraph 2.)

This does not make an exception for when the # punctuator preprocessing token was concatenated, so it appears the "0" is still formed. It is less clear if the # punctuator preprocessing token created from concatenation should be removed too. If the ## is evaluated first, should the result be "\"0\"", "#\"0\"", or something else?

Question 2

S(F(#,0))

Assume the ## is evaluated first for this question. Should the result be "#\"0\"", "##\"0\"", or something else?