Authors: Jay Ghiron
Date: 2026-06-19
Submitted against: C23
Status: Open
For this issue, assume the following macro is always defined:
#define S(...)#__VA_OPT__(__VA_ARGS__)
There are two contexts where the interaction of macro expansion with whitespace is visible. The first is how whitespace is handled when attempting to form header names from sequences of preprocessing tokens. This is intentionally implementation-defined, so it is up to the implementation in how it handles this. The second is whitespace in stringization, and the handling of whitespace is defined clearly here. For example:
#define X 1+2
#define Y 1 + 2
S(X)
S(Y)
This results in "1+2" and "1 + 2". The standard is clear about
this, but implementations disagree about how to handle whitespace when
interacting with arguments or macros which in either case expand to no
preprocessing tokens. GCC, Clang, MSVC, and EDG all agree that when
invoking a macro its arguments do not contain surrounding whitespace:
#define Z(...)__VA_ARGS__
S((Z( 1 )))/* "(1)" not "( 1 )" */
#define E
#define F(X,Y)X Y X
#define G(...)__VA_OPT__(E E)__VA_OPT__(__VA_ARGS__)__VA_OPT__(E E)
#define H(X,...)__VA_OPT__(X X)__VA_OPT__(__VA_ARGS__)__VA_OPT__(X X)
#define I(...)__VA_OPT__() __VA_ARGS__ __VA_OPT__()
#define J(...)__VA_OPT__(E) __VA_ARGS__ __VA_OPT__(E)
#define K(X,...)__VA_OPT__(X) __VA_ARGS__ __VA_OPT__(X)
S((E 1 E+F(,2)+G(3)+H(,4)+I(5)+J(6)+K(,7)+K(8,-)))
S((E E)(F(,))(G())(H())(I())(J())(K()))
What should be the result of these? This is several test cases combined into one, for simplicity. Here are what different compilers generate (MSVC only using its new preprocessor):
"( 1 + 2 + 3 + 4 + 5 + 6 + 7 +8 - 8)" and "( )( )()()( )( )( )"."( 1 +2 + 3 +4 +5 + 6 +7 +8 - 8)" and "( )( )( )( )( )( )( )"."( 1 + 2 + 3 + 4 + 5+ 6+ 7+8 -8)" and "( )( )()()( )( )( )"."( 1+2+3+4+5+ 6+7+8 -8)" and "()()()()()()()"."(1 +2 +3+4 +5 +6 +7 +8 - 8)" and "()()()()()()()".#define L(X,...)__VA_OPT__(X X)##1##__VA_OPT__(X X)
#define M(X,...)__VA_OPT__(X X)## 1 ##__VA_OPT__(X X)
#define N(X,...)__VA_OPT__(X)##1##__VA_OPT__(X)
#define O(X,...)__VA_OPT__(X)## 1 ##__VA_OPT__(X)
#define P(...)__VA_OPT__()##1##__VA_OPT__()
#define Q(...)__VA_OPT__()## 1 ##__VA_OPT__()
#define R(X,...)X##1##X
#define T(X,...)X## 1 ##X
S((L(,,))(L(,))(M(,,))(M(,))(N(,,))(N(,))(O(,,))(O(,))(P(,))(P())(Q(,))(Q())(R(,))(T(,)))
What should be the result of this? Here are what different compilers generate (MSVC only using its new preprocessor):
"( 1 )(1)( 1 )(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)"."(1 )(1 )(1 )(1 )(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)"."(1 )(1)( 1 )( 1)(1)(1)( 1)( 1)(1)(1)( 1)( 1)(1)( 1)"."(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)"."(1 )(1)(1 )(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)".See also C++ CWG 1625 and C++ CWG 2522.
For macros such as __STDC__ or __FILE__ which have a defined
expansion of a single token, can whitespace be inserted around them?
For example:
S((__STDC__))
Must this expand to "(1)", or can it expand to any of "( 1)", "(1 )",
and "( 1 )" as well?