Программирование >>  Дополнительные возможности наследования 

1 ... 217 218 219 [ 220 ] 221 222 223 ... 265


Макросы

Директиву #def ine можно также использовать для создания макросов. Макрос - это лексема, созданная с помощью директивы #define. Он принимает параметры подобно обычной функции. Препроцессор заменяет строку подстановки любым заданным параметром. Например, макрокоманду TWICE можно определить следующим образом:

#define TWICE(x) ( (х) . 2 )

А затем в программе можно записать следующую строку:

TWICE(4)

Целая строка TWICE(4) будет удалена, а вместо нее будет стоять значение 8! Когда препроцессор считывает параметр 4, он выполняет следующую подстановку: ((4) * 2), это выражение затем вычисляется как 4 2 и в результате получается число 8.

Макрос может иметь больше одного параметра, причем каждый параметр в тексте замены может использоваться неоднократно. Вот как можно определить два часто используемых макроса - МАХ и Ml N:

#define МАХ(х,у) ( (х) > (у) (х) : (у) ) #define MIN(x,y) ( (х) < (у) ? (х) : (у) )

Обратите внимание, что в определении макроса открывающая круглая скобка для списка параметров должна немедленно следовать за именем макроса, т.е. между ними не должно быть никаких пробелов. Препроцессор, в отличие от компилятора, не прощает присутствия ненужных пробелов.

Если записать

#define МАХ (х,у) ( (х) > (у) ? (х) : (у) ) и попытаться использовать макрос МАХ

int X = 5, у = 7, z; Z = МАХ(х,у);

то промежуточный код будет иметь следующий вид:

int X = 5, у = 7, z;

Z = (х,у) ( (X) > (у) ? (X) : (у) )(х,у)

В этом случае сделана простая текстовая замена, а не вызов макроса, т.е. лексема МАХ была заменена выражением (х,у) ( (х) > (у) ? (х) : (у) ),за которым сохранилась строка (х,у).

Однако после удаления пробела между словом МАХ и списком параметров (х,у) промежуточный код выглядит уже по-другому:

int X = 5, у = 7, z; Z =7;

Зачем нужны все эшн круглые скоОкн

Вам может показаться странным, что в макросах используется так много круглых скобок. На самом деле препроцессор совсем не требует, чтобы вокруг параметров в строке подстановки ставились круглые скобки, но эти скобки помогают избежать не-



желательных побочных эффектов при передаче макросу сложных значений. Например, если определить МАХ как

tfdefine МАХ(х,у) х > у ? х : у

и передать значения 5 и 7, то макрос МАХ будет нормально работать. Но если передать более сложные выражения, можно получить неожиданные результаты, как показано в листинге 21.2.

Листинг 21.2. ИсиоАЬЗсваиие в макрвсе крувАЫх сквОвк

2 3 4 5 6 7 8 9

10 11 12 13 14 15 16 17 18 19 20 21 22 23

Листинг 21.2. Использование в макросе круглых скобок #include <iostream.h>

#define CUBE(a) ( (a) * (a) (a) ) tfdefine THREE(a) a * a * a

int main() {

long X = 5;

long у = CUBE(x);

long z = THREE(x);

cout << y: << у << endl; cout z: << z endl;

long a = 5, b = 7; у = CUBE(a+b); z = THREE(a+b);

cout y: << у endl; cout z: z << endl; return 0;

125 125 1728 82

В строке 4 определяется макрос CUBE с параметром х, который заключается в круглые скобки при каждом его использовании в выражении. В строке 5 определяется макрос THREE, параметр которого используется без круглых скобок.

При первом использовании этих макросов параметру передается значение 5, и оба макроса прекрасно справляются со своей работой. Макрос CUBE(5) преобразуется в выражение ( (5) (5) (5) ), которое при вычислении дает значение 125, а макрос THREE(5) прейбразуется в выражение 5 5 5, которое также возвращает значение 125.

При повторном обращении к этим макросам в строках 16-18 параметру передается выражение 5 + 7. В этом случае макрос CUBE(5+7) преобразуется в следующее выражение:

( (5+7) . (5+7) . (5+7) )



Подставляемые функции

Часто вместо макросов удобно объявить подставляемую функцию. Например, в листинге 21.3 создается функция CUBE, которая выполняет ту же работу, что и макрос CUBE в листинге 21.2, но в данном случае это делается способом, обеспечивающим контроль за соответствием типов.

( (12) . (12) . (12) )

При вычислении этого выражения получаем значение 1728. Однако макрос THREE(5+7) преобразуется в выражение иного вида;

5 + 7*5 + 7.5 + 7

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

5 + (7 5) + (7 . 5) + 7

После вычисления произведений в круглых скобках получаем выражение 5 + (35) + (35) + 7

После суммирования оно возвращает зггачснис 82.

Макросы в сравнении с функциями шаОлонпв

При работе с макросами п языке С++ можно столкнуться с чегырьмя проблемами. Первая состоит в возможных псудоГ)СТЕ!ах при увеличении самого выражения макроса, поскольку любой макрос должен быть определен в одной строке. Безусловно, эту строку можно продлить с помощью символа обратной косой черты (\), но большие макросы сложны для понимания и с ними грудио работать.

Вторая проблема cocToirr н том. что макросы вьпюлняюгся путем подстановки их выражений в код программы при каждом выюве. Эго озЕИчает, что если макрос используется 12 раз, то ctojhjKo же раз в Biiiuy программу будет вставлено соответствующее выражение (вместо одною рази, как при обращении к обычной функции). Хотя, с другой стороны, подставляемые выражении обычно работают быстрее, чем вызовы функций, поскольку не тратится время па само обращение к функции.

Тот факт, что макросы выполняются путем подстановки выражений в код программы, приводит к третьей проблеме, которая проявляется в том, что макросы огсуг-ствуют в исходном коде программы, используемом компилятором для ее тестирования. Это может существенно затруднить отладку программы.

Однако наиболее существенна послс;цгяя проблема: в макросах не поддерживается контроль за соответствием типов даипых. Хотя возможность ис1гользования в макросе абсолютно любого параметра кажется удобной, эгот факт полностью подрывает строгий контроль типов в С++ и является проклятием для программистов на С++. Конечно, сушествует корректный способ решить и эту проблему - нужно воспользоваться услугами шаблонов, как было показано на занятии 19.



1 ... 217 218 219 [ 220 ] 221 222 223 ... 265

© 2006 - 2025 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика