Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSVC doesn't expand __VA_ARGS__ correctly

Consider this code:

#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__ #define G(...) F(__VA_ARGS__) F(1, 2, 3) G(1, 2, 3) 

The expected output is X = 1 and VA_ARGS = 2, 3 for both macros, and that's what I'm getting with GCC, however, MSVC expands this as:

X = 1 and VA_ARGS = 2, 3 X = 1, 2, 3 and VA_ARGS = 

That is, __VA_ARGS__ is expanded as a single argument, instead of being broken down to multiple ones.

Any way around this?

like image 634
uj2 Avatar asked Feb 27 '11 16:02

uj2


People also ask

What is __ Va_args __ C++?

macro expansion possible specifying __VA_ARGS__ The '...' in the parameter list represents the variadic data when the macro is invoked and the __VA_ARGS__ in the expansion represents the variadic data in the expansion of the macro. Variadic data is of the form of 1 or more preprocessor tokens separated by commas.

What is_ MSc_ ver?

_MSC_VER Defined as an integer literal that encodes the major and minor number elements of the compiler's version number. The major number is the first element of the period-delimited version number and the minor number is the second element. For example, if the version number of the Microsoft C/C++ compiler is 17.00.


2 Answers

Edit: This issue might be resolved by using /Zc:preprocessor or /experimental:preprocessor option in recent MSVC. For the details, please see here.

MSVC's preprocessor seems to behave quite differently from the standard specification.
Probably the following workaround will help:

#define EXPAND( x ) x #define F(x, ...) X = x and VA_ARGS = __VA_ARGS__ #define G(...) EXPAND( F(__VA_ARGS__) ) 
like image 200
Ise Wisteria Avatar answered Sep 19 '22 22:09

Ise Wisteria


I posted the following Microsoft support issue:

The following program gives compilation error because the precompiler expands __VA_ARGS__ incorrectly:

#include <stdio.h>  #define A2(a1, a2) ((a1)+(a2))  #define A_VA(...) A2(__VA_ARGS__)  int main(int argc, char *argv[]) {     printf("%d\n", A_VA(1, 2));     return 0; } 

The preprocessor expands the printf to: printf("%d\n", ((1, 2)+()));

instead of printf("%d\n", ((1)+(2)));

I received the following unsatisfying answer from a Microsoft compiler team developer:

Hi: The Visual C++ compiler is behaving correctly in this case. If you combine the rule that tokens that match the '...' at the inital macro invocation are combined to form a single entity (16.3/p12) with the rule that sub-macros are expanded before argument replacement (16.3.1/p1) then in this case the compiler believes that A2 is invoked with a single argument: hence the error message.

like image 35
dmitryvolk Avatar answered Sep 18 '22 22:09

dmitryvolk