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-8.5.0/cpp/Argument-Prescan.html