С помощью этой директивы задаются макросы, значения которых определяются препроцессором и подставляются в программу вместо имен макросов. Общий синтаксис определения макроса выглядит следующим образом:
Имя макроса задает идентификатор, который будет использоваться при разработке программы. Тело макроса содержит код, которым будет заменено каждое имя макроса, встреченное в программе. Список параметров необязателен и используется для передачи в макрос аргументов. Заметьте, что точка с запятой в конце определения макроса не ставится.
Общепринятой практикой является давать макросам имена, состоящие из прописных букв. В этом случае их легче находить в тексте программы.
В простейшем (и часто используемом) случае в качестве тела макроса указывается обычное константное значение, например:
#define TRUE 1
#define JAN "January"
#define PI 3.141592
...
cout << "Number Pi in " << JAN << " is equal " << Pi;
Здесь вместо макроса JAN будет подставлена строка "January", а вместо имени Pi – конкретное числовое значение. Причем имя Pi, которое указано в строке "Number Pi in ", не будет заменено числом, т.к. заменяются только идентификаторы.
Если определение макроса не умещается на одной строке, то его тело можно перенести на новую строку, поставив в конце строки экранирующий символ \. Например:
#define LONG_STRING "Иногда встречаются длинные макросы, которые для \
удобства чтения программы нужно перенести на новую строку. Для этого \ используются символы обратной косой черты."
Более сложным случаем являются макросы с параметрами, которые по функционалу напоминают функции.
Например:
#define SQR(x) x*x // плохой макрос, не надо так делать
#define MIN(a,b) (((a) < (b)) ? a : b)
...
cout << SQR(2) << endl; // 2*2
cout << SQR(2+1) << endl; // 2+1*2+1
cout << MIN(5.6, 'c');
При обработке макроса его параметры будут заменены реальными аргументами. Это довольно опасное применение макросов, т.к. при этом, в отличие от функций, не производится контроль типов аргументов, а также может оказаться неожиданной последовательность вычисления выражений.
В приведённом выше примере макрос SQR должен вычислять квадрат переданного ему аргумента. Но в некоторых случаях работать он будет неправильно. При первом его использовании – SQR(2) – всё работает корректно, макрос разворачивается в запись 2*2. Но второй вызов даст неожиданный результат. SQR(2+1) вернёт не 9, а 5. Происходит это потому, что макрос разворачивается в выражение 2+1*2+1, порядок выполнения операций в котором оказывается неверным.
Именно по этой причине второй макрос MIN использует такое количество круглых скобок. Так как нельзя заранее угадать какое значение будет передано в качестве параметра, необходимо позаботиться о приоритете операций. Обычно это означает активное использование круглых скобок. Поэтому макросы с параметрами нужно применять осторожно, всегда заключая их параметры в круглые скобки и тщательно просчитывая возможный порядок вычисления тела макроса.
В общем случае параметризованные макросы не рекомендуются к использованию в связи с их неудобным синтаксисом и возможными непредвиденными результатами работы. Вместо них лучше применять функции со спецификатором inline.
Чтобы отменить действие макроса используется директива
#undef имя_макроса
Например
#undef MIN
Макрос действует в программе с момента определения до момента отмены.