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-9.5.0/cpp/Macro-Arguments.html