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 и документация были неверны по этому вопросу, настаивая на том, что для функционоподобного макроса, принимающего один аргумент, необходимо передавать пробел, если нужен пустой аргумент.
Параметры макроса, появляющиеся внутри строковых литералов, не заменяются соответствующими фактическими аргументами.
#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-5.5.0/cpp/Macro-Arguments.html