Jump to content

Вариативный макрос в препроцессоре C

(Перенаправлено из макроса Variadic )

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

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

Синтаксис объявления

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

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

Кроме того, перед макросом могут быть указаны обычные аргументы макроса. ..., [4] но обычные аргументы не могут быть перечислены после ....

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

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

имен макросов в аргументе __VA_OPT__ Правила препроцессора C запрещают рекурсивное расширение . Однако это ограничение можно обойти до произвольного фиксированного числа рекурсивных расширений. [7]

Поддерживать

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

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

Поддержка макроса __VA_OPT__ для поддержки нулевых аргументов была добавлена ​​в GNU Compiler Collection 8. [10] Кланг 6, [11] и Visual Studio 2019 . [12]

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

  1. Наша реализованная функция
    void realdbgprintf (const char *SourceFilename,
                        int SourceLineno,
                        const char *CFormatString,
                        ...);
    
  2. Из-за ограничений поддержки переменных макросов в C++11 следующее: простое решение может потерпеть неудачу, и поэтому его следует избегать:

       #define dbgprintf(cformat, ...) \
         realdbgprintf (__FILE__, __LINE__, cformat, __VA_ARGS__)
    

    Причина в том, что

       dbgprintf("Hallo")
    

    расширяется до

       realdbgprintf (__FILE__, __LINE__, "Hallo", )
    
    где запятая перед закрывающей скобкой приведет к синтаксической ошибке.
  3. GNU C++ поддерживает непереносимое расширение, которое решает эту проблему.
       #define dbgprintf(cformat, ...) \
         realdbgprintf (__FILE__, __LINE__, cformat, ##__VA_ARGS__)
    
  4. C++20 в конечном итоге поддерживает следующий синтаксис.
       #define dbgprintf(cformat, ...) \
         realdbgprintf (__FILE__, __LINE__, cformat __VA_OPT__(,) __VA_ARGS__)
    
  5. Используя строку cformat как часть переменных аргументов, мы можем

    обойти вышеупомянутые несовместимости. Это сложно, но портативный.

    #define dbgprintf(...) realdbgprintf (__FILE__, __LINE__, __VA_ARGS__)
    

dbgprintf() тогда можно было бы назвать как

dbgprintf ("Hello, world");

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

realdbgprintf (__FILE__, __LINE__, "Hello, world");

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

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

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

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

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

Завершающая запятая

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

Существует проблема переносимости при создании завершающей запятой с пустыми аргументами для переменных макросов в C99 . Некоторые компиляторы (например, Visual Studio, если не используется новый препроцессор, соответствующий стандарту) [6] ) автоматически удалит конечную запятую. Другие компиляторы (например: GCC [4] ) поддерживаю ставлю ## перед __VA_ARGS__.

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

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

MYLOG("Too many balloons %u", 42);

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

fprintf (stderr, "%s(%u): " "Too many balloons %u" "\n", __FILE__, __LINE__, 42);

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

fprintf (stderr, "%s(%u): Too many balloons %u\n", __FILE__, __LINE__, 42);

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

MYLOG("Attention!");

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

fprintf (stderr, "%s(%u): " "Attention!" "\n", __FILE__, __LINE__, );

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

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

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

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

C23 решает эту проблему, вводя __VA_OPT__ как С++. [3]

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

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

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

#define dbgprintf(x) realdbgprintf x

dbgprintf() тогда можно было бы назвать так:

dbgprintf (("Hello, world %d", 27));

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

realdbgprintf ("Hello, world %d", 27);
  1. ^ Рабочий проект изменений для синхронизации препроцессора C99 – http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm
  2. ^ «Пропуск и удаление запятой» . 18 июня 2017 г. Проверено 24 декабря 2022 г.
  3. ^ Перейти обратно: а б «WG14 – N3033: Пропуск и удаление запятой» . 20 июля 2022 г.
  4. ^ Перейти обратно: а б с д Вариативные макросы – использование коллекции компиляторов GNU (GCC)
  5. ^ Лоран Денио (16 января 2006 г.). "__ВА_НАРГ__" . новостей : comp.std.c. Группа Usenet:   [электронная почта защищена] .
  6. ^ Перейти обратно: а б с Вариативные макросы (C++)
  7. ^ Рекурсивные макросы с C++20 __VA_OPT__
  8. ^ Изменение исходного кода Clang, в котором упоминается поддержка __VA_ARGS__ (29 июля 2006 г.), обратите внимание, что исходный код Clang был открыт в 2007 году. http://llvm.org/viewvc/llvm-project?view=revision&revision=38770
  9. ^ Сравнение функций Sun Studio – http://developers.sun.com/sunstudio/support/CCcompare.html .
  10. ^ «Поддержка C++2a в GCC» . Проверено 14 июня 2018 г.
  11. ^ «Поддержка C++ в Clang» . Проверено 14 июня 2018 г.
  12. ^ «Обзор нового препроцессора MSVC» . 10 сентября 2020 г. Проверено 8 декабря 2020 г.

См. также

[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 1f3a4e23f7bb4ee540db9e5ec76f8431__1712620380
URL1:https://arc.ask3.ru/arc/aa/1f/31/1f3a4e23f7bb4ee540db9e5ec76f8431.html
Заголовок, (Title) документа по адресу, URL1:
Variadic macro in the C preprocessor - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)