На этом шаге мы рассмотрим правила определения и использования макросов.
Средства макрообработки позволяют определять и обрабатывать макроимена, ориентированные на простую текстовую подстановку, с помощью макроопределений и макровызовов.
Макроопределение имеет вид:
#define <макроимя> <строка_лексем> или #define <макроимя>(<список_параметров>) <строка_лексем>
где макроимя - идентификатор, строка_лексем - последовательность лексем от макроимени до конца строки (точка с запятой в конце не ставится). Существенно, что между макроименем и открывающей круглой скобкой не должно быть пробелов!
Список_параметров макроимени - это список идентификаторов, разделенных запятыми. Строка_лексем также может содержать эти параметры.
Любой макровызов (появление макроимени в качестве отдельной лексемы в тексте программы, расположенном после макроопределения) ведет к замене этого макроимени на указанную строку_лексем. Область действия макроимени - фрагмент программы от точки макроопределения и до конца текста программы.
Макровызов должен быть отдельной лексемой и состоять из макроимени и заключенного в круглые скобки списка аргументов. При обработке макровызова препроцессор заменяет каждый параметр в строке лексем на соответствующий аргумент макровызова. Количество аргументов в макровызове должно соответствовать количеству параметров макроопределения.
Для макровызова действует правило, согласно которому после замены макроимени строка вновь просматривается с целью обнаружения в ней макровызовов. Таким образом, допускаются вложенные макровызовы.
Если в строку замещения входит идентификатор, определенный в другой команде #define, то в строке замещения выполняется следующая замена (цепочка подстановок). Например, программа, содержащая команды:
#define K 50; #define PE cout << "\nКоличество элементов K = " << K . . . . . PE; . . . . .
Количество элементов К = 50
Обратите внимание, что идентификатор к внутри строки замещения, обрамленной кавычками ("), не заменен на 50.
Текст внутри строк, символьные константы и комментарии не подлежат замене, т.к. строки и символьные константы являются неделимыми лексемами языка C++. Так что, после макроопределения
#define YES 1
cout << "YES";
Замены в тексте можно отменять с помощью команды:
#undef <макроимя>
#define M 16 #undef M #define M 'C' #undef M #define M "C"
Директиву #undef удобно использовать при разработке больших программ, когда они собираются из отдельных "кусков текста", написанных в разное время или разными программистами. В этом случае могут встретиться одинаковые обозначения разных объектов. Чтобы не изменять исходных файлов, включаемый текст можно "обрамлять" подходящими директивами #define - #undef и тем самым устранять возможные ошибки. Приведем пример:
. . . . . A = 10; //Основной текст. . . . . . #define A X . . . . . A = 5; //Включенный текст. . . . . . #undef A . . . . . B = A; //Основной текст. . . . . .
Если строка_лексем оказывается слишколм длинной, то ее можно продолжить в следующей строке текста программы. Для этого в конце продолжаемой строки помещается символ "\". В ходе одной из стадий препроцессорной обработки этот символ вместе с последующим символом конца строки будет удален из программы. Например:
#define STROKA "\n Multum, non multa - \
многое, но немного!"
. . . . .
cout << STROKA;
. . . . .
Multum, non multa - многое, но немного!
На следующем шаге мы приведем несколько примеров использования директив препроцессора.