logo
volkov / C++ / Бьерн Страуструп-Справочное руководство по С++

R.16.3 Макроопределение и макроподстановка

Команда вида

#define идентификатор строка-лексем

называется макроопределением. Она указывает препроцессору, что надо

произвести замену всех последующих вхождений идентификатора на заданную

последовательность лексем, называемую строкой замены. Обобщенные

пробелы, окружающие эту последовательность лексем, отбрасываются.

Например, при определении

#define SIDE 8

описание

char chessboard[side][side];

после макроподстановки примет вид

char chessboard[8][8];

Определенный таким способом идентификатор можно переопределить

с помощью другой команды #define, но при условии, что строки

замены в обоих определениях совпадают. Все символы обобщенного

пробела, разделяющие лексемы, считаются идентичными.

Команда вида

идентификатор ( идентификатор, ... ,идентификатор) строка-лексем

называется макроопределением с параметрами или "функциональным"

макроопределением. В нем недопустимы пробелы между первым

идентификатором и символом (. Определенный таким способом

идентификатор можно переопределить с помощью другого функционального

макроопределения, но при условии, что во втором определении

то же число и те же наименования параметров, что и в первом, а обе

строки замены совпадают. Все символы обобщенного пробела, разделяющие

лексемы, считаются идентичными.

Последующие вхождения идентификатора, определенного в

функциональном макроопределении, если за ним следуют символ

(, последовательность лексем, разделенных запятыми, и символ

), заменяются на строку лексем из макроопределения. Обобщенные

пробелы, окружающие строку замены, отбрасываются. Каждое вхождение

идентификатора, из списка параметров макроопределения, заменяется

на последовательность лексем, представляющую соответствующий

фактический параметр в макровызове. Фактическими параметрами являются

строки лексем, разделенные запятыми. Запятая, взятая в кавычки, или

находящаяся в символьной константе или во вложенных круглых скобках,

не разделяет параметров. Число фактических параметров макровызова должно

совпадать с числом параметров макроопределения.

После идентификации параметров для функционального макроопределения

происходит подстановка фактических параметров. После выполнения подстановок

в параметре (если они были) этот параметр в строке замены замещается

фактическим параметром из макровызова ($$R.16.3.3); исключения

составляют случаи, когда параметру предшествует лексема # ($$R.16.3.1),

или с ним соседствует лексема ## ($$R.16.3.2).

Приведем пример. Пусть есть макроопределения

#define index_mask 0XFF00

#define extract(word,mask) word & mask

Тогда макровызов

index = extract(packed_data,index_mask);

после подстановки примет вид

index = packed_data & 0XFF00;

Для обоих видов макроопределений строка замены проверяется на

наличие других макроопределений ($$R.16.3.3).