3.10.6 Предварительный анализ аргументов
Аргументы макроса полностью макрорасширяются перед их подстановкой в тело макроса, если только они не строятся или не склеиваются с другими токенами. После подстановки всё тело макроса, включая подставленные аргументы, снова сканируется на наличие макросов для расширения. В результате аргументы сканируются дважды для расширения вызовов макросов в них.
Большинство времени это не оказывает влияния. Если аргумент содержал какие-либо вызовы макросов, они расширяются во время первого сканирования. Результат, следовательно, не содержит вызовов макросов, поэтому второе сканирование не изменяет его. Если бы аргумент подставлялся как есть, без предварительного сканирования, единственное оставшееся сканирование обнаружило бы те же вызовы макросов и дало бы те же результаты.
Можно ожидать, что двойное сканирование изменит результаты, когда самоссылочный макрос используется в аргументе другого макроса (см. Самоссылочные макросы): самоссылочный макрос будет расширен один раз в первом сканировании и во второй раз во втором сканировании. Однако это не так. Самоссылки, которые не расширяются в первом сканировании, помечаются так, что они не будут расширяться и во втором сканировании.
Можно спросить: «Зачем упоминать предварительный анализ, если он не влияет на результат? И почему не пропустить его и не ускорить работу препроцессора?» Ответ заключается в том, что предварительный анализ оказывает влияние в трёх особых случаях:
- Вложенные вызовы макроса.
Мы говорим, что вложенные вызовы макроса происходят, когда аргумент макроса содержит вызов того же самого макроса. Например, если
f— это макрос, который ожидает один аргумент,f (f (1))— это вложенная пара вызововf. Желаемое расширение создаётся путём расширенияf (1)и подстановкой его в определениеf. Предварительный анализ обеспечивает ожидаемый результат. Без предварительного анализаf (1)сам по себе будет подставлен в качестве аргумента, а внутреннее использованиеfпоявится во время основного сканирования как косвенная самоссылка и не будет расширено. - Макросы, которые вызывают другие макросы, которые строят или конкатенируют.
Если аргумент строит или конкатенирует, предварительный анализ не выполняется. Если вы хотите расширить макрос, затем построить или конкатенировать его расширение, вы можете это сделать, заставив один макрос вызвать другой макрос, который выполняет строку или конкатенацию. Например, если у вас есть
#define AFTERX(x) X_ ## x #define XAFTERX(x) AFTERX(x) #define TABLESIZE 1024 #define BUFSIZE TABLESIZE
тогда
AFTERX(BUFSIZE)расширяется доX_BUFSIZE, аXAFTERX(BUFSIZE)расширяется доX_1024. (Не доX_TABLESIZE. Предварительный анализ всегда делает полное расширение.) - Макросы, используемые в аргументах, чьи расширения содержат не экранированные запятые.
Это может привести к вызову макроса, расширенного во втором сканировании, с неправильным количеством аргументов. Вот пример:
#define foo a,b #define bar(x) lose(x) #define lose(x) (1 + (x))
Мы хотели бы, чтобы
bar(foo)превратилось в(1 + (foo)), которое затем превратится в(1 + (a,b)). Вместо этогоbar(foo)расширяется доlose(a,b), и вы получите ошибку, потому чтоloseтребует одного аргумента. В этом случае проблему легко решить с помощью тех же скобок, которые должны использоваться для предотвращения неправильного вложения арифметических операций:#define foo (a,b)
or
#define bar(x) lose((x))
Дополнительная пара скобок предотвращает интерпретацию запятой в определении
fooкак разделителя аргументов.
Далее: Перевод строки в аргументах, Предыдущее: Самоссылочные макросы, Вверх: Ловушки макросов [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-5.5.0/cpp/Argument-Prescan.html