Важно!Важно помнить, что в C++ предусмотрен еще один способ определения констант, который заключается в использовании спецификатора const. Однако многие программисты "пришли" в C++ из С-среды, где для этих целей обычно использовалась директива #define. Поэтому вам еще часто придется с ней сталкиваться в С++-коде.

Макроопределения, действующие как функции

Директива #define имеет еще одно назначение: макроимя может использоваться с аргументами. При каждом вхождении макроимени связанные с ним аргументы заменяются реальными аргументами, указанными в коде программы. Такие макроопределения действуют подобно функциям. Рассмотрим пример.

/* Использование "функциональных" макроопределений. */

#include

using namespace std;

#define MIN(a, b) (((a)<(b)) ? a : b)

int main()

{

 int x, y;

 x = 10;

 y = 20;

 cout << "Минимум равен: " << MIN(x, у);

 return 0;

}

При компиляции этой программы выражение, определенное идентификатором MIN (а, b), будет заменено, но x и y будут рассматриваться как операнды. Это значит, что cout-инструкция после компиляции будет выглядеть так.

cout << "Минимум равен: " << (((х)<(у)) ? х : у);

По сути, такое макроопределение представляет собой способ определить функцию, которая вместо вызова позволяет раскрыть свой код в строке.

Макроопределения, действующие как функции,это макроопределения, которые принимают аргументы.

Кажущиеся избыточными круглые скобки, в которые заключено макроопределение MIN, необходимы, чтобы гарантировать правильное восприятие компилятором заменяемого выражения. На самом деле дополнительные круглые скобки должны применяться практически ко всем макроопределениям, действующим подобно функциям. Нужно всегда очень внимательно относиться к определению таких макросов; в противном случае возможно получение неожиданных результатов. Рассмотрим, например, эту короткую программу, которая использует макрос для определения четности значения.

// Эта программа дает неверный ответ.

#include

using namespace std;

#define EVEN(a) a%2==0 ? 1 : 0

int main()

{

 if(EVEN(9+1)) cout << "четное число";

 else cout << "нечетное число ";

 return 0;

}

Эта программа не будет работать корректно, поскольку не обеспечена правильная подстановка значений. При компиляции выражение EVEN(9+1) будет заменено следующим образом.

9+1%2==0 ? 1 : 0

Напомню, что оператор "%" имеет более высокий приоритет, чем оператор "+". Это значит, что сначала выполнится операция деления по модулю (%) для числа 1, а затем ее результат будет сложен с числом 9, что (конечно же) не равно 0. Чтобы исправить ошибку, достаточно заключить в круглые скобки аргумент a в макроопределении EVEN, как показано в следующей (исправленной) версии той же программы.

// Эта программа работает корректно.

#include

using namespace std;

#define EVEN(a) (a)%2==0 ? 1 : 0

int main()

{

 if(EVEN(9+1)) cout << "четное число";

 else cout << "нечетное число";

 return 0;

}

Теперь сумма 9+1 вычисляется до выполнения операции деления по модулю. В общем случае лучше всегда заключать параметры макроопределения в круглые скобки, чтобы избежать непредвиденных результатов, подобных описанному выше.

Использование макроопределений вместо настоящих функций имеет одно существенное достоинство: поскольку код макроопределения расширяется в строке, и нет никаких затрат системных ресурсов на вызов функции, скорость работы вашей программы будет выше по сравнению с применением обычной функции. Но повышение скорости является платой за увеличение размера программы (из-за дублирования кода функции).

Перейти на страницу:

Все книги серии Изучайте C++ с профессионалами

Похожие книги