MSVC неправильно расширяет __VA_ARGS__
Рассмотрим этот код:
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) F(__VA_ARGS__)
F(1, 2, 3)
G(1, 2, 3)
Ожидаемый результат X = 1 and VA_ARGS = 2, 3
для обоих макросов, и это то, что я получаю с GCC, однако, MSVC расширяет это как:
X = 1 and VA_ARGS = 2, 3
X = 1, 2, 3 and VA_ARGS =
То есть, __VA_ARGS__
раскрывается как один аргумент, а не разбивается на несколько аргументов.
Есть ли способ обойти это?
3 ответа
Препроцессор MSVC, похоже, ведет себя совершенно иначе, чем стандартная спецификация.
Вероятно, поможет следующее решение проблемы:
#define EXPAND( x ) x
#define F(x, ...) X = x and VA_ARGS = __VA_ARGS__
#define G(...) EXPAND( F(__VA_ARGS__) )
Я разместил следующую проблему поддержки Microsoft:
Следующая программа выдает ошибку компиляции, потому что прекомпилятор разворачивается
__VA_ARGS__
неправильно:#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; }
Препроцессор расширяет printf до: printf("%d\n", ((1, 2)+()));
вместо printf("%d\n", ((1)+(2)));
Я получил следующий неудовлетворительный ответ от разработчика команды компиляторов Microsoft:
Привет: Компилятор Visual C++ ведет себя правильно в этом случае. Если вы объединяете правило, что токены, которые соответствуют '...' при первоначальном вызове макроса, объединяются, чтобы сформировать единую сущность (16.3/p12) с правилом, что вложенные макросы раскрываются перед заменой аргумента (16.3.1/p1)) тогда в этом случае компилятор считает, что A2 вызывается с одним аргументом: отсюда и сообщение об ошибке.
Какую версию MSVC вы используете? Вам понадобится Visual C++ 2010.
__VA_ARGS__
был впервые представлен C99. MSVC никогда не пытался поддерживать C99, поэтому поддержка не была добавлена.
Теперь, однако, __VA_ARGS__
включен в новый стандарт C++, C++2011 (ранее известный как C++0x), который Microsoft, очевидно, планирует поддерживать, поэтому он был поддержан в последних версиях MSVC.
Кстати, вам нужно будет использовать .cpp
суффикс к вашему исходному файлу, чтобы получить эту поддержку. MSVC долгое время не обновлял свой C-интерфейс.