Директива #define. Как уже иллюстрировалось на примере именованных констант, для замены выбранного программистом идентификатора заранее подготовленной последовательностью символов используется директива (обратите внимание на пробелы):
#define идентификатор строка_замещения
Директива может размещаться в любом месте обрабатываемого текста, а ее действие в обычном случае распространяется от точки размещения до конца текста. Директива, во-первых, определяет идентификатор как препроцессорный. В результате работы препроцессора вхождения идентификатора, определенного командой #define, в тексте программы заменяются строкои замещения, окончанием которои обычно служит признак конца той "физическои" строки, где размещена команда #define. Символы пробелов, помещенные в начале и в конце строки замещения, в подстановке не используются.
Цепочка подстановок
Если в строке _замещения команды
#define в качестве отдельной лексемы встречается препроцессорный идентификатор, ранее определенный другой директивой #define, то выполняется цепочка последовательных подстановок.
Замены не выполняются внутри комментариев, внутри строковых констант, внутри символьных констант и внутри идентификаторов (не может измениться часть идентификатора) т.е. не распространяются на тексты, ограниченные кавычками ("), апострофами (') и разделителями (/*, */).
Если строка_замещения оказывается слишком длинной, то, ее можно продолжить в следующей строке текста. Для этого в конце продолжаемой строки помещается символ '\'.
Пример:
#define STRING "\n Game Over! - \
Игpa зaкoнчeнa!"
printf(STRING);
Ha экpaн бyдeт вывeдeнo:
Game Over! - Игpa эaкoнчeнa!
Видно, что строка замещения может содержать перечисленные ограничители.
Если в программе нужно часто печатать или выводить на экран дисплея значение какой-либо переменной и, кроме того, снабжать эту печать одним и тем же пояснительным текстом, то удобно ввести сокращенное обозначение оператора печати, например:
#define PK printf("\n Hoмep элeментa=%d•", N);
После этой директивы использование в программе оператора РК; будет эквивалентно (по результату) оператору из строки замещения- Например, последовательность операторов
int N = 4;
PK;
приведет к выводу такого текста:
Номер элемента=4.
Если в строку замещения входит идентификатор, определенный в другой команде #define, то в строке замещения выполняется цепочка подстановок. Например, программа, содержащая команды:
#define K 50
#define PE printf ("\n Чиcлo элeмeнтoв K=%d",K);
PE;
вывeдeт нa экpaн тaкoй тeкcт:
Чиcлo элeмeнтos K=50
Обратите внимание, что идентификатор К внутри строки за-мещения, обрамленной кавычками ("), не заменен на 50.
Строку замещения, связанную с конкретным препроцессор-ным идентификатором, можно сменить, приписав уже определенному идентификатору новое значенне другой командой #define:
#define M 16
/* Идeнтификaтop M oпpедeлeн кaк 16 */
#define M 'C'
/* M oпpeдeлeн кaк cимвoльнaя кoнcтaнтa 'C'
#define M "C"
/* M onpeдeлeн кaк cимвoльнaя cтpoкa */ /* c двyмя элeмeнтaми: 'C' и '\0' */
Однако при таких сменах значений препроцессорного иден-ификатора компилятор Вог1апс1 С++ выдает предупреждающее ообщение на каждую следующую директиву.
Замены в тексте можно отменять с помощью команды
#undef идeнтификaтop
После выполнения такой директивы идентификатор для препроцессора становится неопределенным, и его можно определять повторно. Например, не вызовут предупреждающих сообщений директивы:
#define M 16
#undef M
#define M 'C'
#undef M
#define M "C"
Директиву #undef удобно использовать при разработке больших программ, когда они собираются из отдельных "кусков текста", написанных в разное время или разными программистами. В этом случае могут встретиться одинаковые обозначения разных объектов. Чтобы не изменять исходных файлов, включаемый текст можно "обрамлять" подходящими директивами #define, #undef и тем самым устранять возможные ошибки.