- •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. Компиляция "налету"
- •Дополнительная литература
- •Интерфейсы
- •Отладка
- •Тестирование
- •Производительность
- •Переносимость
Интерфейсы
Прячьте детали реализации.
Ограничьтесь небольшим набором независимых примитивов.
Не делайте ничего "за спиной" у пользователя.
Всегда делайте одинаковое одинаково.
Высвобождайте ресурсы на том же уровне, где выделяли их.
Обнаруживайте ошибки на низком уровне, обрабатывайте на
высоком. Используйте исключения только для исключительных
ситуаций.
Отладка
Ищите знакомые ситуации.
Проверьте самое последнее изменение.
Не повторяйте дважды одну и ту же ошибку.
Не откладывайте отладку на потом.
Пользуйтесь стеком вызова.
Читайте код перед тем, как исправлять.
Объясните свой код кому-либо еще.
Сделайте ошибку воспроизводимой.
Разделяй и властвуй.
Изучайте нумерологию ошибок.
Выводите информацию, локализующую место ошибки.
Пишите код с самоконтролем.
Ведите журнальный файл.
Постройте график.
Используйте инструменты.
Ведите записи.
Тестирование
Тестируйте граничные условия кода.
Тестируйте пред- и постусловия.
Используйте утверждения.
Используйте подход защитного программирования.
Проверяйте коды возврата функций.
Тестируйте по возрастающей.
Тестируйте сначала простые блоки.
Четко определите, чего вы ожидаете на выходе теста.
Проверяйте свойства сохранности данных.
Сравните независимые версии.
Оценивайте охват тестов.
Автоматизируйте возвратное тестирование.
Создавайте замкнутые тесты.
Производительность
Автоматизируйте замеры времени.
Используйте профилировщик.
Концентрируйтесь на критических местах.
Постройте график.
Улучшайте алгоритм и структуру данных.
Используйте оптимизацию компилятора.
Выполните тонкую настройку кода.
Не оптимизируйте то, что не имеет значения.
Объединяйте общие выражения.
Замените дорогостоящие операции на более дешевые.
Избавьтесь от циклов или упростите их.
Кэшируйте часто используемые значения.
Напишите специальную функцию захвата памяти (аллокатор).
Буферизуйте ввод и вывод.
Специальные случаи обрабатывайте отдельно.
Используйте предварительное вычисление результатов.
Используйте приближенные значения.
Перепишите код на языке более низкого уровня.
Используйте минимально возможный тип данных.
Не храните то, что можете без труда вычислить.
Переносимость
Придерживайтесь стандарта.
Следуйте основному руслу.
Избегайте неоднозначных конструкций языка.
Попробуйте несколько компиляторов.
Используйте стандартные библиотеки.
Используйте только то, что доступно везде.
Избегайте условной компиляции.
Выносите системные различия в отдельные файлы.
Прячьте системные различия за интерфейсами.
Используйте текст для обмена данными.
Используйте при обмене данными фиксированный порядок байтов.
При изменении спецификации изменяйте и имя.
Поддерживайте совместимость с существующими программами и данными.
Не рассчитывайте на ASCII.
Не ориентируйтесь только на английский язык.
1 Слово "иерархическая" означает, что указание на другие вершины создает своего рода непосредственную подчиненность вершин, и корню косвенно подчинены все остальные вершины. Здесь речь идет только о направленных деревьях, в других приложениях дерево определяется несколько иначе.
2 Простой пример использования нисходящего порядка — вычисление расстояний от корня до всех вершин или пропускных способностей путей. Термины pre-order, post-order и in-order переводятся у нас по-разному, например — КЛП-, ЛПК- и ЛКП-порядки. Не следует употреблять термины из первого издания "Искусства программирования" Д. Кнута, сам автор вскоре исправил эти термины.
3 "Show me your flowcharts and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won't usually need your flowcharts; they'll be obvious".
4 Примечательно, что сама эта техника появилась при исследовании А. А. Марковым закономерностей чередования букв в русском тексте (конкретно ~ в романе А. С. Пушкина "Евгений Онегин").
5 Авторы пишут на протяжении всей книги "алгоритм Маркова", но в русской литературе этот термин связан с именем другого человека, А. А. Маркова-младшего. Выбором латинского написания мы постарались отстранить алгоритм от конкретных лиц.
6 Чтобы читатель представил себе получающийся текст, мы пропустили через программу текст Книги Псалмов на русском языке. При этом все буквы были сделаны строчными, а знаки препинания убраны, так как русская система падежей обеспечивает достаточное управление. Вот один из "псалмов":
спаси меня от делающих беззаконие спаси от кровожадных ибо вот они подстерегают душу мою милостив господь и достохвален страшен он для всех любящих оные дело его слава и красота и правда его пребывает во веки и веки
В эту траекторию вошло 16 переходов с однозначным выбором.
7 По моему личному опыту, лучше объяснять программу не мужчинам, а жен щинам: они чувствуют неуверенность в вашем голосе, когда вы объясняете трудное для вас место, и начинают "копаться" в нем, требуя более подробных объяснений.
8 При построении подобных графиков удобно выводить данные для него в упоминавшемся формате CSV, а затем использовать электронные таблицы.
9 RCS (Revision Control System) — система, предназначенная для сравнения версий программных систем и сохранения истории их развития. Документацию по этой системе легко найти в Интернете.
10 В работе этой программы существенно используется определение функции | getc, которую вызывает макрофункция getchar, данное стандартом ANSI С: эта | функция всегда возвращает число в диапазоне от 0 до UCHAR_MAX. Напомним, что | в распространенной системе Turbo С следование стандарту зависит от установки ключей и в режиме по умолчанию getc указанным свойством не обладает.
11 Awk — аббревиатура, составленная по именам авторов: А - Ахо, W — Вайн-бергер и К — Керниган, один из авторов этой книги.
12 Структура данных "бор" описана у Кнута в книге "Искусство программирования для ЭВМ. Сортировка и поиск",с. 572-581. Вкратце, это хэш-таблица, элементами которой являются двоичнырованные деревья.
13 Это типичный случай так называемой редкозаполненной матрицы, объекта, очень часто встречающегося в современных вычислениях. В каждом конкретном алгоритме выбор способа представления такой матрицы существенно зависит от кластера (набора) необходимых операций и от частот их использования.
14 Добавим немного детален: байт вида Оххххххх используется для однобайтовой кодировки символов, байт вида 10хххххх -- для расширения многобайтовых представлений, байт вида 110ххххх и байт 1110хххх начинают, соответственно, двух- и трехбайтовые представления. Для наиболее интересующих нас двухбайтовых представлений, в которые помешается кириллица, полумается 2048 возможностей.
15 В русском переводе "Гулливера в стране лилипутов", когда речь идет о политической важности вопроса о том, с какого конца есть яйцо, эти термины переведены как "тупоконечники" и "остроконечники".
16 Аналогично, [b-e] обозначает множество символов, идущих подряд от b до е, то есть в задании шаблона можно пользоваться диапазонами символов.
17 Не следует путать такое поведение с поведением жадных (также greedy) оптимизационных алгоритмов, при работе которых отказ от выбранных решений исключается.
18 В языке Форт реализована именно такая стековая машина, о которой пишут авторы. Отметим, что такие же идеи используются и в ПостСкрипте, о котором как-то было сказано, что он "больше Форт, чем сам Форт".
19 Макросредства С удобно использовать и для решения задачи из предыдущего параграфа о списке ошибок. Можно описать каждую ошибку макросом с двумя параметрами и дважды условно компилировать список ошибок, получая обе требуемые конструкции из одного источника.
20 В современной русскоязычной компьютерной литературе термин JIT зачастую не переводят, то есть так и пишут — "JIT-компиляторы"; этот же термин будем использовать и мы.
21 Разработанная Д. Кнутом технология "грамотного программирования" описана в его книге (Knuth D. Literate, Programming. Center for the Study of Language and Information, 1992). Программную поддержку этого подхода можно найти в Интернете.
