Spec-Zone.ru › GCC 10 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 препроцессора и документация были неверны в этом вопросе, настаивая на том, что макросу с одним аргументом должен передаваться пробел, если требуется пустой аргумент.

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

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

Spec-Zone.ru

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