Spec-Zone.ru › GCC 4 CPP

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API