10.2 Традиционные макросы
Основное различие между традиционными и ISO-макросами заключается в том, что первые расширяются до текста, а не до последовательности токенов. CPP удаляет все начальные и конечные горизонтальные пробелы из заменяющего текста макроса перед его сохранением, но сохраняет форму внутренних пробелов.
Одним следствием является то, что в заменяющем тексте может быть непарная кавычка (см. Традиционный лексический анализ). Незакрытая строка или символьный констант продолжается в текст после вызова макроса. Аналогично, текст в конце расширения макроса может слиться с текстом после вызова макроса, образуя один токен.
Обычно комментарии удаляются из заменяющего текста после расширения макроса, но если опция -CC передается в командной строке, комментарии сохраняются. (На самом деле, текущая реализация удаляет комментарии даже перед сохранением заменяющего текста макроса, но делает это таким образом, чтобы наблюдаемый эффект был идентичен даже в случае макроса функционального типа).
Оператор строкового форматирования ISO ‘#’ и оператор склейки токенов ‘##’ не имеют специального значения. Как объяснено позже, подобный эффект этих операторов можно получить иным способом. Имена макросов, вставленные в кавычки, как из основного файла, так и после замены макроса, не расширяются.
CPP заменяет имя неограниченного объектного макроса своим заменяющим текстом, а затем повторно сканирует его для поиска других макросов для замены. В отличие от стандартного расширения макросов, традиционное расширение макросов не предусматривает предотвращения рекурсии. Если объектный макрос появляется без кавычек в его заменяющем тексте, он будет заменён снова во время повторного сканирования, и так далее до бесконечности. GCC обнаруживает, когда расширяет рекурсивные макросы, выводит сообщение об ошибке и продолжает после вызова нарушающего макроса.
#define PLUS +
#define INC(x) PLUS+x
INC(foo);
→ ++foo;
Функциональные макросы по форме похожи, но поведением сильно отличаются от своих ISO-аналогов. Их аргументы заключены в скобки, разделены запятыми и могут занимать несколько физических строк. Запятые в вложенных скобках не обрабатываются как разделители аргументов. Аналогично, кавычка в аргументе не может быть оставлена незакрытой; следующая запятая или скобка, предшествующая закрывающей кавычке, обрабатывается как любой другой символ. Нет механизма для обработки вариативных макросов.
В этой реализации все комментарии из аргументов макроса удаляются, если не указана опция -C. Формат всех других горизонтальных пробелов в аргументах сохраняется, включая начальные и конечные пробелы. В частности
f( )
обрабатывается как вызов макроса ‘f’ с одним аргументом, состоящим из одного пробела. Если вы хотите вызвать функциональный макрос, который не принимает аргументов, не оставляйте пробелов между скобками.
Если аргумент макроса переносится на новую строку, новая строка заменяется пробелом при формировании аргумента. Если предыдущая строка содержала незакрытую кавычку, следующая строка наследует состояние кавычки.
Традиционные препроцессоры заменяют параметры в заменяющем тексте их аргументами независимо от того, находятся ли параметры в кавычках или нет. Это обеспечивает способ форматирования аргументов. Например
#define str(x) "x"
str(/* A comment */some text )
→ "some text "
Обратите внимание, что комментарий удален, но конечный пробел сохранён. Вот пример использования комментария для склейки токенов.
#define suffix(x) foo_/**/x
suffix(bar)
→ foo_bar
Далее: Традиционные мелочи, Предыдущий: Традиционный лексический анализ, Вверх: Режим традиционных макросов [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-5.5.0/cpp/Traditional-macros.html