Макрос с переменными числами

редактировать

A вариационный макрос - это функция некоторых компьютерных языков программирования, особенно препроцессора C, посредством чего может быть объявлено, что макрос принимает различное количество аргументов..

Макросы с переменными аргументами были введены в 1999 году в версии ISO / IEC 9899: 1999 (C99 ) языкового стандарта C, и в 2011 году в версии ISO / IEC 14882: 2011 (C ++ 11 ) стандарта языка C ++. Поддержка вариативных макросов без аргументов была добавлена ​​в C ++ 20.

Содержание
  • 1 Синтаксис объявления
  • 2 Поддержка
  • 3 Пример
  • 4 Завершающая запятая
  • 5 Альтернативы
  • 6 Ссылки
  • 7 См. Также
Синтаксис объявления

Синтаксис объявления аналогичен синтаксису вариативных функций : последовательность из трех точек " ..."используется, чтобы указать, что необходимо передать один или несколько аргументов. Во время раскрытия макроса каждое появление специального идентификатора __VA_ARGS__в списке замены макроса заменяется переданными аргументами.

Не предусмотрено никаких средств для доступа к отдельным аргументам в списке переменных аргументов или для определения количества переданных аргументов. Однако можно написать макросы для подсчета числа переданных аргументов.

Оба стандарта C99 и C ++ 11 требуют по крайней мере одного аргумента, но начиная с C ++ 20 это ограничение было снято с помощью функционального макроса __VA_OPT__. Макрос __VA_OPT__заменяется своим аргументом, если присутствуют аргументы, и опускается в противном случае. Однако общие компиляторы также позволяют передавать нулевые аргументы перед этим добавлением.

Поддержка

Некоторые компиляторы поддерживают макросы с переменными аргументами при компиляции кода C и C ++: GNU Compiler Collection 3.0, Clang (все версии), Visual Studio 2005, C ++ Builder 2006 и Oracle Solaris Studio (ранее Sun Studio) Forte Developer 6, обновление 2 (C ++ версии 5.3). GCC также поддерживает такие макросы при компиляции Objective-C.

. Поддержка макроса __VA_OPT__для поддержки нулевых аргументов была добавлена ​​в GNU Compiler Collection 8, Clang 6, но особенно не Visual Studio 2017.

Пример

Если printf -подобная функция dbgprintf (), который принимает в качестве аргументов файл и номер строки, из которой он был вызван, применимо следующее решение.

// Наша реализованная функция void realdbgprintf (const char * SourceFilename, int SourceLineno, const char * CFormatString,...); // Из-за ограничений поддержки вариативных макросов в C ++ 11 следующее // простое решение может потерпеть неудачу, и его следует избегать: // // #define dbgprintf (cformat,...) \ // realdbgprintf (__FILE__, __LINE__, cformat, __VA_ARGS__) // // Причина в том, что // // dbgprintf ("Hallo") // // расширяется до // // realdbgprintf (__FILE__, __LINE__, "Hallo",) // // где запятая перед закрывающей фигурной скобкой приведет к синтаксической ошибке. // // GNU C ++ поддерживает непереносимое расширение, которое решает эту проблему. // // #define dbgprintf (cformat,...) \ // realdbgprintf (__FILE__, __LINE__, cformat, ## __ VA_ARGS__) // // C ++ 20 в конечном итоге поддерживает следующий синтаксис. // // #define dbgprintf (cformat,...) \ // realdbgprintf (__FILE__, __LINE__, cformat __VA_OPT __ (,) __VA_ARGS__) // // Используя строку 'cformat' как часть аргументов с переменным числом аргументов, мы можем / / обойти вышеупомянутые несовместимости. Это сложно, но // переносимо. #define dbgprintf (...) realdbgprintf (__FILE__, __LINE__, __VA_ARGS__)

dbgprintf ()затем может вызываться как

dbgprintf ("Привет, мир");

, который заменяется на

realdbgprintf (__FILE__, __LINE__, «Привет, мир»);

Другой пример:

dbgprintf ("% d +% d =% d", 2, 2, 5);

, который расширяется до

realdbgprintf (__ FILE__, __LINE__, "% d +% d =% d", 2, 2, 5);

Без вариативных макросов запись оболочки в printf напрямую невозможна. Стандартный обходной путь - использовать функциональные возможности C / C ++ stdargs и вместо этого использовать вызов функции vprintf .

Конечная запятая

Возникла проблема переносимости при создании конечной запятой с пустыми аргументами для макросов с переменным числом аргументов в C99. Некоторые компиляторы (например, Visual Studio) автоматически удаляют запятую. Другие компиляторы (например: GCC) поддерживают размещение ##перед __VA_ARGS__.

# define MYLOG (FormatLiteral,...) fprintf (stderr, "% s (% u):" FormatLiteral "\ n", __FILE__, __LINE__, __VA_ARGS__)

Следующее приложение работает

MYLOG («Слишком много баллов% u», 42);

, который заменяется на

fprintf (stderr, "% s (% u):" "Слишком много всплывающих подсказок% u" "\ n", __FILE__, __LINE__, 42);

, что эквивалентно

fprintf (stderr, "% s (% u): слишком много баллов% u \ n", __FILE__, __LINE__, 42);

Но посмотрите на это приложение:

MYLOG («Внимание!»);

, который расширяется до

fprintf (stderr, "% s (% u):" "Внимание!" "\ N", __FILE__, __LINE__,);

, который генерирует синтаксическую ошибку с GCC.

GCC поддерживает следующее (непереносимое) расширение:

# define MYLOG (FormatLiteral,...) fprintf (stderr, "% s (% u):" FormatLiteral "\ n", __FILE__, __LINE__, ## __ VA_ARGS__)

который удаляет конечную запятую, когда __VA_ARGS__пусто.

Альтернативы

До появления переменных-аргументов в C99 было довольно распространено использовать двояко вложенные круглые скобки для использования переменного числа аргументов, которые могли быть переданы в printf ()function:

# define dbgprintf (x) realdbgprintf x

dbgprintf ()затем может вызываться как:

dbgprintf (("Привет, мир% d", 27));

, который расширяется до:

realdbgprintf ("Привет, мир% d", 27);
Ссылки
См. Также
Последняя правка сделана 2021-06-18 09:52:51
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте