8.3.4. Проблемы макросов

8.3.4. Проблемы макросов

Средства макрорасширения были излюбленной тактикой разработчиков языков в ранней Unix. Язык С, несомненно, имеет такое средство. Кроме того, они обнаруживаются в некоторых более сложных мини-языках специального назначения, таких как pic(1). Препроцессор m4 предоставляет общее средство для реализации макрорасширяющих препроцессоров.

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

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

Для языка С классическим примером такой проблемы является макрос, подобный следующему.

#define max(x, у) х > у ? x : у

Данный макрос создает как минимум две проблемы. Одна из них заключается в том, что он может вызвать непредсказуемые результаты, в случае если один из аргументов является выражением, включающим в себя оператор меньшего приоритета, чем > или ?:. Рассмотрим выражение max(а = b, ++с). Если программист забыл, что max является макросом, то он будет ожидать, что присваивание a = b и преинкрементная операция с с будут выполнены до того, как результирующие значения будут переданы max в качестве аргументов.

Однако это не так. Вместо этого препроцессор преобразует данное выражение в a = b > ++c ? a = b : ++c, которое правила приоритета компилятора С заставляют интерпретировать как a = (b > ++c ? a = b : ++c). Результат будет присвоен а.

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

#define max(x, у) ((x) > (у) ? (х) : (y))

С таким определением выражение будет развернуто как ((a = b) > (++с) ? (а = b) : (++c)), что решает одну проблему, однако следует заметить, что переменная с может быть инкрементирована дважды. Существуют менее очевидные варианты данной проблемы, такие как передача макросу вызова функции с побочными эффектами.

Как правило, взаимодействие между макросами и выражениями с побочными эффектами может привести к неудачным результатам, которые трудно диагностировать. Макропроцессор С умышленно создан легковесным и простым. Более мощные макропроцессоры способны действительно вызвать более серьезные проблемы.

Язык форматирования TEX (см. главу 18) хорошо иллюстрирует общую проблему. ТеХ — умышленно разрабатывался как язык Тьюринга (в нем имеются условные операции, циклы и рекурсия), однако, несмотря на то, что его можно заставить делать поразительные вещи, TEX-код часто нечитабельный и трудный в отладке. Исходные коды для LATEX, наиболее широко используемого TEX-макропакета, являются поучительным примером: они созданы в очень хорошем TEX-стиле, но даже несмотря на это их крайне трудно понять.

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

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

Каскады макрорасширений, встроенные в язык, могут выполнять самокоррекцию, обрабатывая номера строк так, чтобы создать ссылки на текст до расширения. Так работает, например, макросредство утилиты pic(1). Данную проблему гораздо труднее решить, когда макрорасширение выполняется препроцессором.

В препроцессоре С проблема решается путем создания директив #line каждый раз, когда выполняется включение или многострочное расширение. Ожидается, что C-компилятор интерпретирует их и соответственно скорректирует номера строк в отчетах об ошибках. К сожалению, в макропроцессоре m4 подобное средство отсутствует.

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

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Создание макросов

Из книги Photoshop. Мультимедийный курс автора Мединов Олег

Создание макросов Давайте в качестве примера создадим макрос, который последовательно будет выполнять следующие действия.• Уменьшать размер изображения на 50 %.• Автоматически выравнивать уровни каналов.• Применять фильтр Резкость.Для создания макросов в редакторе


9.2. Создание макросов

Из книги Word 2007.Популярный самоучитель автора Краинский И

9.2. Создание макросов Самый простой способ создания макроса – запись нужных действий в документе. Записав последовательность команд один раз, можно будет вызывать макрос щелчком кнопкой мыши, когда нужно будет выполнять такие же действия. Для записи макросов сделайте


9.4. Экспорт и импорт макросов

Из книги Искусство программирования для Unix автора Реймонд Эрик Стивен

9.4. Экспорт и импорт макросов Часто бывает так, что внутренний макрос может оказаться полезным при работе на другом компьютере. В этом случае просто нужно экспортировать его во внешний. Для этого сделайте следующее.1. Откройте окно Макрос щелчком на кнопке Макросы на


8.3.4. Проблемы макросов

Из книги UNIX: взаимодействие процессов автора Стивенс Уильям Ричард

8.3.4. Проблемы макросов Средства макрорасширения были излюбленной тактикой разработчиков языков в ранней Unix. Язык С, несомненно, имеет такое средство. Кроме того, они обнаруживаются в некоторых более сложных мини-языках специального назначения, таких как pic(1).


Пример: упрощение с помощью макросов

Из книги Стандарты программирования на С++. 101 правило и рекомендация автора Александреску Андрей

Пример: упрощение с помощью макросов В листинге 9.3 установка и снятие блокировки занимали шесть строк кода. Мы должны выделить место под структуру, инициализировать ее и затем вызвать fcntl. Программы можно упростить, если определить следующие семь макросов, которые взяты


16. Избегайте макросов

Из книги VBA для чайников автора Каммингс Стив

16. Избегайте макросов РезюмеМакрос — самый неприятный инструмент С и С++, оборотень, скрывающийся под личиной функции, кот, гуляющий сам по себе и не обращающий никакого внимания на границы ваших областей видимости. Берегитесь его!ОбсуждениеТрудно найти язык, достаточно


Планирование макросов

Из книги Первые шаги с Windows 7. Руководство для начинающих автора Колисниченко Денис Н.

Планирование макросов Прежде чем вы пропустите этот тоскливый раздел и с головой погрузитесь в процесс записи макросов, выслушайте один довольно консервативный совет: чтобы избежать лишней головной боли, уделите немного времени планированию макроса перед тем, как


Запись макросов

Из книги Access 2002: Самоучитель автора Дубнов Павел Юрьевич

Запись макросов К счастью, записывать макросы так же просто, как ложиться в постель. Тем более, что я собираюсь разложить здесь вам все по полочкам. Запуск средства записи макросов Запустить средство записи макросов можно одним из следующих способов.* Выбрать из меню


Выполнение макросов

Из книги Linux программирование в примерах автора Роббинс Арнольд

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


Простейшие усовершенствования макросов

Из книги автора

Простейшие усовершенствования макросов В этой главе не предполагается подробно рассматривать приемы редактирования макросов в редакторе Visual Basic. В конце концов, это те же самые приемы, которые используются при создании любых VBA-программ и которые, в основном,


3.6. Включение/выключение макросов MS Office

Из книги автора

3.6. Включение/выключение макросов MS Office Поддержка макросов в OOo Writer очень посредственная, но она есть. Однако по умолчанию макросы MS Office вообще отключены. Для включения возможности выполнения макросов выполните команду меню Сервис | Параметры. Перейдите в раздел


Функции макросов

Из книги автора

Функции макросов Макросы бывают двух видов: единичные, то есть состоящие из одной макрокоманды, и сложные. В последнем случае макрос включает несколько последовательно выполняемых макрокоманд, объединенных общим именем. Каждая макрокоманда осуществляет определенную


Использование макросов для обработки событий

Из книги автора

Использование макросов для обработки событий Наиболее часто макросы применяются для обработки событий. При этом макрос может функционировать и как самостоятельная программа, и в составе процедуры VBA (Visual Basic for Applications). Первый вариант мы рассмотрим в этом разделе, а