- •1. Стиль 10
- •3. Проектирование и реализация 63
- •4. Интерфейсы 85
- •5. Отладка 115
- •6. Тестирование 134
- •7. Производительность 157
- •8. Переносимость 180
- •9. Нотация 203
- •Введение
- •Брайан в. Керниган
- •1.1. Имена
- •1.2. Выражения
- •Упражнение 1 -6
- •1.3. Стилевое единство и идиомы
- •1.4. Макрофункции
- •1.5. Загадочные числа
- •1.6. Комментарии
- •1.7. Стоит ли так беспокоиться?
- •Дополнительная литература
- •2.1. Поиск
- •2.2. Сортировка
- •2.3. Библиотеки
- •2.4. Быстрая сортировка на языке Java
- •2.5. "О большое"
- •2.6. Динамически расширяемые массивы
- •2.7. Списки
- •Упражнение 2-8
- •2.8. Деревья
- •Упражнение 2-15
- •2.10. Заключение
- •Дополнительная литература
- •Проектирование и реализация
- •3.1. Алгоритм цепей Маркова
- •3.2. Варианты структуры данных
- •3.3. Создание структуры данных в языке с
- •3.4. Генерация вывода
- •3.5.Java
- •Into the air. When water goes into the air it
- •3.7. Awk и Perl
- •3.8. Производительность
- •3.9. Уроки
- •Дополнительная литература
- •4. Интерфейсы
- •4.1. Значения, разделенные запятой
- •4.2. Прототип библиотеки
- •4.3. Библиотека для распространения
- •Упражнение 4-4
- •4.5 Принципы интерфейса
- •4.6. Управление ресурсами
- •4.7. Abort, Retry, Fail?
- •4.8. Пользовательские интерфейсы
- •Дополнительная литература
- •5. Отладка
- •5.1. Отладчики
- •5.2. Хорошие подсказки, простые ошибки
- •5.3, Трудные ошибки, нет зацепок
- •5.4. Последняя надежда
- •5.5. Невоспроизводимые ошибки
- •5.6. Средства отладки
- •5.7. Чужие ошибки
- •5.8. Заключение
- •Дополнительная литература
- •6. Тестирование
- •6.1. Тестируйте при написании кода
- •6.2. Систематическое тестирование
- •6.3. Автоматизация тестирования
- •6.4. Тестовые оснастки
- •6.5. Стрессовое тестирование
- •6.6. Полезные советы
- •6.7. Кто осуществляет тестирование?
- •6.8. Тестирование программы markov
- •6.9. Заключение
- •Дополнительная литература
- •7.Производительность
- •7.1. Узкое место
- •7.2. Замеры времени и профилирование
- •7.3. Стратегии ускорения
- •7.4. Настройка кода
- •7.5. Эффективное использование памяти
- •7.6. Предварительная оценка
- •7.7. Заключение
- •Дополнительная литература
- •8. Переносимость
- •8.1. Язык
- •8.2. Заголовочные файлы и библиотеки
- •8.3. Организация программы
- •8.4. Изоляция
- •8.5. Обмен данными
- •8.6. Порядок байтов
- •8.7. Переносимость и внесение усовершенствований
- •8.8. Интернационализация
- •8.9. Заключение
- •Дополнительная литература
- •9.1. Форматирование данных
- •9.2. Регулярные выражения
- •Упражнение 9-12
- •9.3. Программируемые инструменты
- •9.4. Интерпретаторы, компиляторы и виртуальные машины
- •9.5. Программы, которые пишут программы
- •9.6. Использование макросов для генерации кода
- •9.7. Компиляция "налету"
- •Дополнительная литература
- •Интерфейсы
- •Отладка
- •Тестирование
- •Производительность
- •Переносимость
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-версию и автоматизировала бы запуск тестов на производительность.
