10.2 Традиционные макросы
Основное различие между традиционными и ISO-макросами заключается в том, что первые расширяются до текста, а не до последовательности токенов. Препроцессор CPP удаляет все начальные и конечные горизонтальные пробелы из текста замены макроса перед его сохранением, но сохраняет внутренние пробелы.
Следствием этого является то, что в тексте замены допустимо наличие непарной кавычки (см. Традиционный лексический анализ). Незакрытая строка или символ константы продолжаются в текст после вызова макроса. Аналогично, текст в конце расширения макроса может сливаться с текстом после вызова макроса, образуя один токен.
Обычно комментарии удаляются из текста замены после расширения макроса, но если опция -CC передается в командной строке, комментарии сохраняются. (На самом деле, текущая реализация удаляет комментарии даже перед сохранением текста замены макроса, но делает это таким образом, что наблюдаемый эффект идентичен даже в случае макроса типа функции.)
Оператор строкового отображения ‘#’ и оператор склейки токенов ‘##’ не имеют специального значения. Как будет объяснено позже, подобный эффект этих операторов может быть получен другим способом. Имена макросов, заключенные в кавычки, как из основного файла, так и после замены макроса, не расширяются.
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-4.9.4/cpp/Traditional-macros.html