Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
kernigan_paik.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.91 Mб
Скачать

9.6. Использование макросов для генерации кода

Опустившись на пару уровней, можно говорить о макросах, которые пишут код во время компиляции. На протяжении всей книги мы предо­стерегали вас от использования макросов и условной компиляции, по­скольку этот стиль программирования вызывает множество проблем. Однако же они все равно существуют, и иногда текстуальная подстановка - это именно то, что нужно для решения данной проблемы. Один из таких примеров - использование препроцессора C/C + + для компонов­ки программы с большим количеством повторяющихся частей

Например, программа из главы 7, оценивающая скорость конструкций простейшего языка, использует препроцессор С для компоновки тестов, составляя из них последовательность стереотипных кодов. Суть теста — заключить фрагмент кода в цикл, который запускает таймер, выполняет этот фрагмент много раз, останавливает таймер и сообщает о результатах. Весь повторяющийся код заключен в пару макросов, а измеряемый код передается в качестве аргумента. Первичный макрос имеет такой вид:

#define LOOP(CODE) { \

t0 = clock(); \

for (i=0; i < n; i++) { CODE; } \

printf("%7d ", clock() - t0); \

}

Обратная косая черта (\) позволяет записывать тело макроса в несколь­ких строках. Этот макрос используется в "операторах", которые имеют такой вид:

LOOP(f1 = f2)

LOOP(f1 = f2 + f3)

LOOP(f1 = f2 - f3)

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

Иногда макросы могут использоваться и для генерации нормального коммерческого кода. Барт Локанти (Bart Locanthi) однажды написал эффективную версию оператора двумерной графики. Этот оператор, на­зываемый bitblt, или rasterop, трудно было сделать быстрым, посколь­ку он использовал большое количество аргументов, которые могли ком­бинироваться самыми хитрыми способами. Проведя тщательный разбор вариантов, Локанти уменьшил комбинации до независимых циклов, ко­торые можно было оптимизировать по отдельности. Затем каждый слу­чай был воссоздан с помощью макроподстановки, аналогичной той, что показана в примере на тестирование производительности, и все вариан­ты были перебраны в одном большом выражении switch. Оригинальный исходный код представлял две-три сотни строк, после выполнения мак­роподстановок он разрастался до многих тысяч строк. Этот конечный код был не самым оптимальным, но, учитывая сложность задачи, весьма практичным и простым в написании. И кстати, как и весь код самого вы­сокого уровня, неплохо переносимым.19

Упражнение 9-16

В упражнении 7-7 вам предлагалось написать программу, оценивающую затраты на различные операции в C++. Используя идеи, изложенные в по­следнем парафафе, попробуйте написать новую версию этой программы.

Упражнение 9-17

В упражнении 7-8 надо было построить модель оценки затрат для Java, а в этом языке нет макросов. Попробуйте решить эту проблему, на­писав другую программу — на любом другом языке (или языках), кото­рая создавала бы Java-версию и автоматизировала бы запуск тестов на производительность.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]