Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 46
Текст из файла (страница 46)
Кроме того, необходимо предостеречь читателей: следуйте соглашению об использовании в именах макросов преимущественно заглавных букв. Синтаксис макросов описан в з Л.11. Простой макрос определяется слсдуюшнм образом: №йеЯпе лгАМЕгее1о1'1!ле Когда встречается лексема МАМЕ, она замешается на гез1 ой 11пе. Например: алтей = МАМЕ будет преобразовано в лагпей = геег оТ 1(пе Макрос люжно определить с аргументами. Например: №йеЯпе МАС (х, у) агуигпеп11: х агуигпепт2: у Прп использовании МАС должны присутствовать лва строковых аргумента. Онп за- менят х н упри макроподстановке. Например, результатом макроподстановки ехралйей = МАС (1оо Ьаг, уиЬ уи)г) будет ехрапйей = агуитеп11:?оо Ьагагуислеп12 уиу уиЬ Имена макросов нельзя перегружать.
Кроме того, рекурсивные вызовы создают про- блемы, которые препропессор не может решить: №йе17леРИНТ(а,Ь) соиг«(и) «(6) №йе1т)пе Р1с!уТ(а, Ь, с) соиг«(а) «(6) « ,'с) Дпрооила? замещение, а не лереерузка №йеЯпе ГАС (п) (п>1) Э и" ГАС(п — 1В 1 1',г лробгела: рекурсивньа( макрос Макросы манппузшруют ст роками символов и маею что знагот о синтаксисе Сьэ и ничего — о типах С-ь ° и областях видимости имен. Компилятор видит текст только после макроподстановки, поэтому п ошибка в макросе будет замечена после подстановки, а не в месте его определения.
Это может привести к очень странным сообщениям об ошибках. Вот несколько прилгеров приемлемых макросов: №йе1гле САБЕ Ьгеау;саве №йе11 ле ГОРЕУЕй1ог (,) Профайлер — инструментальное средство, предназначенное для нзмерсвия проязводнгельвостп, расхода памяти и других параметров работы программы. — Прил~ел ред Глава 7. Функции 204 Вот несколько примеров совершенно ненужных макросов: №йе/)не Р73,141593 пнете НЕБИТ ( №«1еЯпе ЕЛ«(З ) Несколько «опасных» макросов: №Ие/1№е 5«К4АРЕ (а) а*а №«1е~~пе 1ЯСй хх (хх)»» Чтобы убедиться, что онн опасны, попытайтесь осуществить макрополстановку в следующих примерах: //тобапьныйскептик 1п1хх = Ок ооиЧ() ( 1п1хх = О; т1 у = 51гиМЕ (хх+2), 1Л«СЕ хх, //хокальная переменная // у=як+2'хх+2; то ест»у=як+(2 хх) 2 //инкрементхокальной хх 1п1 Ьас№сай (); Директива № оп«(е/Х Если вам необходимо использовать макросы, пользуйтесь оператором разрешения области видимости с при обращении к глобальным переменным Ц 4.9А) и везде, где это только возможно, заключайте имя аргумента макроса в скобки.
Например: №с(еЯпеМЕ»' (а, Ь) (((а) < (Ь)) 2 (и): (Ь)) Если вы написали сложный макрос, который требует комментариев, лучше пользо- ваться комментариями /* "/, потому что препроцессор С, который не знает о //-стиле комментариев, иногда используется как часть среды С++. Например: №йе/сне М2 (а) еотег№1пу (а) /* правильный коя№1ентарий*/ При помощи макросов вы можете создать свой собственный язык. Даже если вы предпочитаете такой «улучшенный» язык обыкновенному С+ +, для других и рограм- мистов на С++ он будет непонятен. Более того, препроцессор С является очень про- стым макро-процессором.
Когда вы попытаетесь сделать что-нибудь нетривиальное, скорее всего окажется, что это либо невозможно, либо слишком трудоемко. Механиз- мы сопв1, )пйпе (встраивание тела функции в место ее вызова), 1етр(а1е (шаблоны), епит и патеврасе (пространства имен) создавались в качестве альтернативы тради- ционному использованию препроцессора. Например: сопв1 с№1 шттег = 42; 1етр!иге<с(аев Т гп()пе Тт(п (Та, ТЬ) ( ге1игп (а<Ь) 2 а; Ь; ) Прн написании макроса иногда требуется новое имя для чего-нибудь.
Строку можно создать при помощи конкатенации двух строк макро-оператором №№. Например: №йе/1пе Л«АМЕ2 (а, Ь) а№№Ь тгЛ«АМЕ2 (Ьас№, саЬ) (), Результатом булет 205 7.9 Советы гарантирует, что более не существует макроса по имени Х независимо от того, существовал ли макрос с таким именем до этой директивы, Это обеспечивает некоторый механизм защиты от нежелательных макросов. Однако, не всегда легко узнать, какое действие Хдолжен был бы оказывать макрос Хна фрагмент кода. ?.8.1. Условная компиляция 11очти невозможно избежать применения макросов в одном случае. Директива №ф1е~ иден1пификатор заставляет компилятор (при выполнении условия) игнорировать последующий текст, пока не встретится директива №епй1. Например: па 1т11п1 а №ф1е~агу ива , 1п16 №епй? выдает компилятору )пГЯп1 а если макрос по имени агу 1во не был определен (№ЫеДпе). Подобный пример приводит в замешательство инструменты разработки, которые ожидают разумного поведения от программиста.
В больпгнпстве случаев использование №ф1е~менее загадочно и, при наличии определенных ограничений, приносит мало вреда. См. также 9 9.3.3. Имена макросов, используемые в № арфе~ следует тщательно выбирать, чтобы они не совпадали с обычными идентификаторами. Например: зГгисГ Са!Е тХо ( Мог)е' агу опе, 6/адв" ага" Пса, Этот невинный текст вызовет неприятные последствия, если кто-нибудь напишет; идеале агу Пса х К сожалению, в неизбежных заголовочных файлах общего пользования содержится множество опасных н ненужных макросов.
?.9. Советы )1] Относитесь с подозрением к пеконстантным аргументам; если вы хотите, чтобы функция модифицировала свои аргументы, пользуйтесь вместо этого указателями и возвращаемым значением; 9 5.5. 121 Если необходимо минимизировать затраты на копирование аргументов, пользуйтесь константными ссылками в качестве аргументов; 9 5.5. 13) 1Лспользуйтс модификатор сопз1регулярно н последовательно; 9 7.2. Глава 7. Функции 206 [4] Избегайте применения макросов; й 7.8.
[5] Избегайте функций с неуказанным количеством аргументов; ~ 7.6. [6] Не возвращайте указатели или ссылки па локальные переменные; (] 7.3. [7] Используйте перегрузку, когда функции выполняют концептуально схожую работу цад объектами различных тинов; й 7.4. [8] При перегрузке функций с целыми аргументамп реализуйтедостаточное количество функции для устранения типичных случаев неоднозначности; 6 7».3. [9] Если ны собираетесь воспользоваться указателем на функцию, подумайте, не будет ли виртуальная функция (~ 2.5.5) или шаблон Я 2.7.2) лучшей аль гернативой; й 7.7. [10] Если вам приходится использовать макросы, дайте им некрасивые, броса>ощиеся в глаза имена с большим количеством заглавных букв; й 7.8. 7.10. Упражнения 1.
(*1) Напишите следующие объявления; функция с аргументами «указатель на символ» и «ссылка на целое», которая не возвращает значение; указатель па такую функцию; фуикцин> с таким указателем в качес > ве,плум ен еа, функцию, возвращающая такой указатель. Напишите определение функции, которая принимает такой указатель в качестве аргумента и возвращает его. Подсказка: воспользуйтесь тдрее1е~.
2. («2) Что означает следующее? Для чего это может пригодиться? Турейе~1лГ ',Ьг>78] (1лб 1лй, 3. (*15) Напишите программу типа «Здранствуй мир!», которая получает имя человека в качестве параметра командной строки и выводит «Здравствуй, и яя(». Измените про>)>амму таким образом, чтобы она получала произвольное количество имен-аргументов и здоровалась с каждым из обладателей имен. 4. ('1.5) Напишите программу, которая читает произвольное количество файлов, чьп имена задаются н командной строке, и выводит их один за друп>м в соий Так как эта программа осуществляет конкатенацию своих аргументов для создания вынода, вы можете назвать ее сай 5, ('2) Перепишите небольшую С-программу па С+».
Модпфицируйте заголовочные файлы таким образом, чтобы в них были объявлены все вызываемые функции и типы всех аргументов. Где возможно замените ПИеЯле па ели>л, соиМ илп >л((ле. Удалите обьянления ех(егл из файлон .си, если необходимо, приведите определения функций к синтаксису С++. Замените вызовы >лаИос (] и 7 ее (] на леп>и е(е1е1е. Удалите ненужные приведения типов. 6. (*2) Реализуйте ззог( (] Я 7.7) с использованием более эффективного алгоритма.
Подсказка:>?логу(]. 7. (*2.5) Имеется: е1гиеГ Тлоае ( еШлд щогс1; гл1соилй Тло>1е' 1«76 Тлоае' г1дв 6 207 7.10. Упражнения 8. ("2.5) Напишите функцшо, которая транспонирует двумерный массив, то есть строки превращает в сто чбпы, а столбцы — в строки. Подсказка: в В.7. 9. (*2) Напишите программу шифрования, которая читает из сш п записывает закоди- пг?еТлпе РТ = 3.14159а; Пг1е~те МллХ )а, Ь) а>Ь?а Ь Пг1еЯпе Тас )а))а)*Тес 1,'а) — Д 10. 11.
12 13. 14. 15, 16. 17. 18. 19. Напшпите функцию добавления новых слов в дерево с узлалш Тпог7е. Напишите функцию вывода такого дерева. Напишите функцшо вывода дерева с Тпог?е в алфавитном порядке. Измените Тпол(е таким образом, чтобы зта структура содержала (только) указатель на произвольно длинное слово, хранящееся (воспользуйтесь оператором аеш) в виде массива символов в свободной памяти.
Измените функции для работы с новым определением Тпог(е. ровапные символы в соий Вы можете воспользоваться следующей простой схемой кодировки: кодом, соответствуюсцему символу с, является с" пер[1], где йеу — строка, переданная в качестве параметра командной строки. Программа использует ц пкли- чески символы из пеу до тех пор, пока не будет счптан весь ввод. В результате по- вторной шифровки закодированного текста с тем же ключом ((лед) получится исход- ная строка.