Spec-Zone.ru › GCC 12 CPP

3.3 Аргументы макросов

Макросы, похожие на функции, могут принимать аргументы, как и настоящие функции. Чтобы определить макрос, использующий аргументы, введите параметры в скобки в определении макроса, делая макрос похожим на функцию. Параметры должны быть допустимыми идентификаторами C, разделенными запятыми и необязательно пробелами.

Для вызова макроса, принимающего аргументы, запишите имя макроса, за которым следует список фактических аргументов в скобках, разделенных запятыми. Вызов макроса не должен быть ограничен одной логической строкой — он может занимать столько строк в исходном файле, сколько потребуется. Количество аргументов должно совпадать с количеством параметров в определении макроса. При раскрытии макроса каждое использование параметра в его теле заменяется токенами соответствующего аргумента. (Вы можете не использовать все параметры в теле макроса.)

В качестве примера, вот макрос, вычисляющий минимум из двух числовых значений, как это определено во многих программах на C, и некоторые примеры его использования.

#define min(X, Y)  ((X) < (Y) ? (X) : (Y))
  x = min(a, b);          →  x = ((a) < (b) ? (a) : (b));
  y = min(1, 2);          →  y = ((1) < (2) ? (1) : (2));
  z = min(a + 28, *p);    →  z = ((a + 28) < (*p) ? (a + 28) : (*p));

(В этом небольшом примере вы уже можете увидеть несколько опасностей связанных с аргументами макросов. Подробное объяснение см. в разделе Особенности макросов.)

Пробелы в начале и конце каждого аргумента отбрасываются, и все пробелы между токенами аргумента сводятся к одному пробелу. Скобки внутри каждого аргумента должны быть сбалансированы; запятая внутри таких скобок не завершает аргумент. Однако нет требования к балансировке квадратных скобок или фигурных скобок, и они не препятствуют разделению аргументов запятыми. Таким образом,

macro (array[x = y, x + 1])

передает два аргумента макросу macro: array[x = y и x + 1]. Если вы хотите предоставить array[x = y, x + 1] в качестве аргумента, вы можете записать его как array[(x = y, x + 1)], что эквивалентно коду C.

Все аргументы макроса полностью раскрываются макросами перед их подстановкой в тело макроса. После подстановки весь текст снова сканируется на предмет макросов для раскрытия, включая аргументы. Это правило может показаться странным, но оно тщательно разработано, чтобы вам не нужно было беспокоиться о том, является ли какой-либо вызов функции фактически вызовом макроса. Однако вы можете столкнуться с проблемами, если попытаетесь быть слишком умным. Подробное обсуждение см. в разделе Предварительное сканирование аргументов.

Например, min (min (a, b), c) сначала раскрывается до

min (((a) < (b) ? (a) : (b)), (c))

а затем до

((((a) < (b) ? (a) : (b))) < (c)
 ? (((a) < (b) ? (a) : (b)))
 : (c))

(Переводы строк, показанные здесь для ясности, фактически не будут сгенерированы.)

Вы можете оставить аргументы макроса пустыми; это не ошибка для препроцессора (но многие макросы затем развернутся в некорректный код). Вы не можете полностью опустить аргументы; если макрос принимает два аргумента, то должен быть ровно один знак запятой на верхнем уровне списка аргументов. Вот несколько забавных примеров с использованием min:

min(, b)        → ((   ) < (b) ? (   ) : (b))
min(a, )        → ((a  ) < ( ) ? (a  ) : ( ))
min(,)          → ((   ) < ( ) ? (   ) : ( ))
min((,),)       → (((,)) < ( ) ? ((,)) : ( ))

min()      error→ macro "min" requires 2 arguments, but only 1 given
min(,,)    error→ macro "min" passed 3 arguments, but takes just 2

Пробел не является токеном препроцессора, поэтому, если макрос foo принимает один аргумент, foo () и foo ( ) оба передают ему пустой аргумент. Предыдущие реализации и документация GNU preprocessor содержали неточности по этому вопросу, настаивая на том, что для макроса, подобного функции, принимающему один аргумент, требуется пробел, если требуется пустой аргумент.

Параметры макроса, появляющиеся внутри строковых литералов, не заменяются соответствующими фактическими аргументами.

#define foo(x) x, "x"
foo(bar)        → bar, "x"

Далее: Строковая обработка, Предыдущий: Макросы, подобные функциям, Наверх: Макросы [Содержание][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-12.1.0/cpp/Macro-Arguments.html

Spec-Zone.ru

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