- •Оглавление
- •Об авторе
- •Благодарности
- •Предисловие
- •Глава 1. Держим оборону
- •На пути к хорошему коду
- •Готовьтесь к худшему
- •Что такое защитное программирование?
- •Этот страшный, ужасный мир
- •Технологии защитного программирования
- •Выберите хороший стиль кодирования и пользуйтесь крепкой архитектурой
- •Пишите код без спешки
- •Не верьте никому
- •Стремитесь к ясности, а не к краткости
- •Не позволяйте никому лезть туда, где ему нечего делать
- •Включайте вывод всех предупреждений при компиляции
- •Пользуйтесь средствами статического анализа
- •Применяйте безопасные структуры данных
- •Проверяйте все возвращаемые значения
- •Аккуратно обращайтесь с памятью (и другими ценными ресурсами)
- •Инициализируйте все переменные там, где вы их объявили
- •Объявляйте переменные как можно позже
- •Пользуйтесь стандартными средствами языка
- •Пользуйтесь хорошими средствами регистрации диагностических сообщений
- •Выполняйте приведение типов с осторожностью
- •Подробности
- •Ограничения
- •Какие ограничения налагать
- •Снятие ограничений
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 2. Тонкий расчет
- •Да в чем проблема?
- •Знайте своих клиентов
- •Что такое хорошее представление?
- •Размещение скобок
- •Скобки в стиле K&R
- •Расширенный стиль скобок
- •Стиль Уайтсмита (с отступами)
- •Другие стили скобок
- •Единственно верный стиль
- •Внутрифирменные стили (и когда их придерживаться)
- •Установка стандарта
- •Религиозные войны?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 3. Что в имени тебе моем?
- •Зачем нужны хорошие имена?
- •Каким объектам мы даем имена?
- •Игра в названия
- •Описательность
- •Техническая корректность
- •Идиоматичность
- •Тактичность
- •Технические подробности
- •Имена переменных
- •Имена функций
- •Имена типов
- •Пространства имен
- •Имена макросов
- •Имена файлов
- •Роза пахнет розой
- •Соблюдайте единообразие
- •Связывайте имя с содержимым
- •Извлекайте выгоду из выбора имени
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 4. Литературоведение
- •Самодокументируемый код
- •Техника написания самодокументируемого кода
- •Пишите простой код с хорошим форматированием
- •Выбирайте осмысленные имена
- •Разбивайте код на самостоятельные функции
- •Выбирайте содержательные имена типов
- •Применяйте именованные константы
- •Выделяйте важные фрагменты кода
- •Объединяйте взаимосвязанные данные
- •Снабжайте файлы заголовками
- •Правильно обрабатывайте ошибки
- •Пишите осмысленные комментарии
- •Практические методологии самодокументирования
- •Грамотное программирование
- •Инструментарий документирования
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 5. Заметки на полях
- •Что есть комментарий в коде?
- •Как выглядят комментарии?
- •Сколько комментариев требуется?
- •Что помещать в комментарии?
- •Не нужно описывать код
- •Не подменяйте код
- •Как сделать комментарии полезными
- •Не отвлекаться
- •На практике
- •Замечание об эстетичности
- •Единообразие
- •Четкие блочные комментарии
- •Отступы в комментариях
- •Комментарии в конце строки
- •Помощь в чтении кода
- •Стиль должен обеспечивать легкость сопровождения
- •Границы
- •Флажки
- •Комментарии в заголовке файла
- •Работа с комментариями
- •Помощь при написании программ
- •Заметки об исправлении ошибок
- •Устаревание комментариев
- •Сопровождение и бессодержательные комментарии
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 6. Людям свойственно ошибаться
- •Откуда что берется
- •Механизмы сообщения об ошибках
- •Без обработки ошибок
- •Возвращаемые значения
- •Переменные, содержащие состояние ошибки
- •Исключения
- •Сигналы
- •Обнаружение ошибок
- •Обработка ошибок
- •Когда обрабатывать ошибки
- •Варианты реагирования
- •Последствия для кода
- •Подымаем скандал
- •Управление ошибками
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 7. Инструментарий программиста
- •Что такое инструмент программирования?
- •А зачем они нужны – инструменты?
- •Электроинструменты
- •Выясните, каковы его возможности
- •Научитесь им управлять
- •Выясните, для каких задач он пригоден
- •Убедитесь, что он работает
- •Имейте четкие данные о том, как получить дополнительные сведения
- •Узнайте, как получить новые версии
- •Какой инструмент необходим?
- •Средства редактирования исходного кода
- •Средства построения кода
- •Инструменты для отладки и тестирования
- •Средства поддержки языка
- •Инструменты различного назначения
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 8. Время испытаний
- •Проверка на подлинность
- •Кто, что, когда, зачем?
- •Зачем тестировать
- •Кому тестировать
- •В чем состоит тестирование
- •Когда тестировать
- •Типы тестирования
- •Выбор контрольных примеров для блочного тестирования
- •Архитектура и тестирование
- •Руками не трогать!
- •Анатомия провала
- •Справлюсь ли я сам?
- •Система контроля ошибок
- •Обсуждение ошибок
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 9. Поиск ошибок
- •Реальные факты
- •Природа этого зверя
- •Взгляд с высоты птичьего полета
- •Взгляд с поверхности земли
- •Взгляд из глубины
- •Борьба с вредителями
- •Обходная дорога
- •Правильный путь
- •Охота за ошибками
- •Ошибки этапа компиляции
- •Ошибки этапа исполнения
- •Как исправлять ошибки
- •Профилактика
- •Отладчик
- •Средство проверки доступа к памяти
- •Трассировщик системных вызовов
- •Дамп памяти
- •Журналирование
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 10. Код, который построил Джек
- •Языковые барьеры
- •Интерпретируемые языки
- •Компилируемые языки
- •Делаем слона из мухи
- •Выполнение сборки
- •Что должна уметь хорошая система сборки?
- •Простота
- •Единообразие
- •Повторяемость и надежность
- •Атомарность
- •Борьба с ошибками
- •Механика сборки
- •Выбор целей
- •Уборка
- •Зависимости
- •Автоматическая сборка
- •Конфигурация сборки
- •Рекурсивное применение make
- •Мастер на все руки
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 11. Жажда скорости
- •Что такое оптимизация?
- •От чего страдает оптимальность кода?
- •Доводы против оптимизации
- •Альтернативы
- •Нужна ли оптимизация
- •Технические подробности
- •Убедитесь, что нужна оптимизация
- •Определите самую медленную часть кода
- •Тестирование кода
- •Оптимизация кода
- •После оптимизации
- •Методы оптимизации
- •Конструктивные изменения
- •Модификация кода
- •Как писать эффективный код
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 12. Комплекс незащищенности
- •Риски
- •Наши оппоненты
- •Оправдания, оправдания
- •Ощущение незащищенности
- •Опасный проект и архитектура
- •Переполнение буфера
- •Встроенные строки запросов
- •Условия гонки
- •Целочисленное переполнение
- •Дела защитные
- •Технология установки системы
- •Технология конструирования программного обеспечения
- •Технологии реализации кода
- •Технологии процедуры
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 13. Важность проектирования
- •Программирование как конструкторская работа
- •Что нужно проектировать?
- •Хороший проект программного продукта
- •Простота
- •Элегантность
- •Модульность
- •Хорошие интерфейсы
- •Расширяемость
- •Избегайте дублирования
- •Переносимость
- •Идиоматичность
- •Документированность
- •Как проектировать код
- •Методы и процедуры проектирования
- •Инструменты проектирования
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 14. Программная архитектура
- •Что такое программная архитектура?
- •План программы
- •Точки зрения
- •Где и когда этим заниматься?
- •Для чего она применяется?
- •Компоненты и соединения
- •Какими качествами должна обладать архитектура?
- •Архитектурные стили
- •Без архитектуры
- •Многоуровневая архитектура
- •Архитектура с каналами и фильтрами
- •Архитектура клиент/сервер
- •Компонентная архитектура
- •Каркасы
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 15. Программное обеспечение – эволюция или революция?
- •Гниение программного обеспечения
- •Тревожные симптомы
- •Как развивается код?
- •Вера в невозможное
- •Как с этим бороться?
- •Как писать новый код
- •Сопровождение существующего кода
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 16. Кодеры
- •Мартышкин труд
- •Нетерпеливый
- •Кодер (Code Monkey)
- •Гуру
- •Псевдогуру
- •Высокомерный гений
- •Ковбой
- •Плановик
- •Ветеран
- •Фанатик
- •Монокультурный программист
- •Лодырь
- •Руководитель поневоле
- •Идеальный программист
- •И что из этого следует?
- •Для глупцов
- •Резюме
- •План действий
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 17. Вместе мы – сила
- •Команды – общий взгляд
- •Организация команды
- •Методы управления
- •Разделение ответственности
- •Организация и структура кода
- •Инструменты для групповой работы
- •Болезни, которым подвержены команды
- •Вавилонская башня
- •Диктатура
- •Демократия
- •Большой Каньон
- •Зыбучие пески
- •Лемминги
- •Личное мастерство и качества, необходимые для работы в команде
- •Общение
- •Скромность
- •Разрешение конфликтов
- •Обучение и приспособляемость
- •Знание пределов своих возможностей
- •Принципы групповой работы
- •Коллективное владение кодом
- •Нормы кодирования
- •Определите, что считать успехом
- •Установите ответственность
- •Избегайте истощения
- •Жизненный цикл команды
- •Создание команды
- •Рост команды
- •Групповая работа
- •Роспуск команды
- •Резюме
- •План действий
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 18. Защита исходного кода
- •Управление версиями исходного кода
- •Контроль версий
- •Контроль доступа
- •Работа с хранилищем
- •Пусть растут деревья
- •Краткая история систем контроля за исходным кодом
- •Управление конфигурацией
- •Резервное копирование
- •Выпуск исходного кода
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 19. Спецификации
- •Что же это такое, конкретно?
- •Типы спецификаций
- •Спецификация требований
- •Функциональная спецификация
- •Спецификация системной архитектуры
- •Спецификация интерфейса пользователя
- •Проектная спецификация
- •Спецификация тестирования
- •Что должны содержать спецификации?
- •Процесс составления спецификаций
- •Почему мы не пишем спецификации?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Когда проводить рецензирование?
- •Нужно ли рецензировать
- •Какой код рецензировать
- •Проведение рецензирования кода
- •Рецензирование на собраниях
- •Интеграционное рецензирование
- •Пересмотрите свое отношение
- •Позиция автора
- •Позиция рецензента
- •Идеальный код
- •За пределами рецензирования кода
- •Резюме
- •Контрольный список
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 21. Какой длины веревочка?
- •Выстрел в темноте
- •Почему трудно делать оценки?
- •Под давлением
- •Практические способы оценки
- •Игры с планами
- •Не отставай!
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 22. Рецепт программы
- •Стили программирования
- •Структурное программирование
- •Функциональное программирование
- •Логическое программирование
- •Рецепты: как и что
- •Процессы разработки
- •Каскадная модель
- •SSADM и PRINCE
- •Создание прототипов
- •Итеративная и инкрементная разработка
- •Спиральная модель
- •Другие процессы разработки
- •Спасибо, хватит!
- •Выбор процесса
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 23. За гранью возможного
- •Программирование приложений
- •Коробочные продукты
- •Заказные приложения
- •Программирование игр
- •Системное программирование
- •Встроенное программное обеспечение
- •Программирование масштаба предприятия
- •Численное программирование
- •И что дальше?
- •Резюме
- •Контрольные вопросы
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 24. Что дальше?
- •Но что же дальше?
- •Ответы и обсуждение
- •Глава 1. Держим оборону
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 2. Тонкий расчет
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 3. Что в имени тебе моем?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 4. Литературоведение
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 5. Заметки на полях
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 6. Людям свойственно ошибаться
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 7. Инструментарий программиста
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 8. Время испытаний
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 9. Поиск ошибок
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 10. Код, который построил Джек
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 11. Жажда скорости
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 12. Комплекс незащищенности
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 13. Важность проектирования
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 14. Программная архитектура
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 15. Программное обеспечение – эволюция или революция?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 16. Кодеры
- •Вопросы для размышления
- •Глава 17. Вместе мы – сила
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 18. Защита исходного кода
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 19. Спецификации
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 20. Рецензия на отстрел
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 21. Какой длины веревочка?
- •Вопросы для размышления
- •Вопросы личного характера
- •Глава 22. Рецепт программы
- •Вопросы для размышления
- •Глава 23. За гранью возможного
- •Вопросы для размышления
- •Вопросы личного характера
- •Библиография
- •Алфавитный указатель
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
222m |
|||||
|
|
|
|
||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
. |
|
|
|
|
|
.c |
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
df |
|
|
n |
e |
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
Глава 9. Поиск ошибокClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
программного обеспечения отладка бывает значительно затруднена по причине более скудной инструментальной поддержки. Возмож% но также, что ваша среда обеспечивает плохую защиту от вашей собственной глупости; ваши мелкие ошибки будут иметь крупные последствия.
•Одно из самых мощных средств в арсенале отладчика – недоверие к чужому коду в совокупности со здоровой дозой цинизма. Причи% ной ошибочного поведения может быть все, что угодно, и, присту% пая к диагностике, вы должны проверять даже самых маловероят% ных кандидатов.
Когда вы ищете ошибку, не верьте никому. Проверьте самые невероятные причины, вместо того чтобы сходу отвергнуть их. Не принимайте ничего на веру.
Охота за ошибками
Как искать ошибки? Если бы существовала какая%нибудь простая трехшаговая процедура, мы бы ее выучили и стали выпускать идеаль% ные программы. Нет такой процедуры, и наши программы такие, ка% кие они есть. Попробуем разобраться в опыте поиска ошибок, накоп% ленном человечеством.
Ошибки этапа компиляции
Мы рассмотрим их первыми, потому что с ними относительно легко бороться. Когда компилятор натыкается на что%то неприятное для не% го, он обычно не просто останавливается, чтобы сообщить об этом, но, пользуясь случаем, оглашает все, что думает о жизни в целом, и разра% жается целой серией новых сообщений об ошибках. Так его учили; найдя ошибку, компилятор пытается по возможности продолжить синтаксический анализ. Это ему редко хорошо удается, но чего еще можно ожидать при таком коде, как ваш?
Результатом является то, что последующие сообщения компилятора могут иметь весьма случайный и необоснованный характер. Смотреть нужно только на самое первое сообщение об ошибке и решать пробле% му с ней. Однако не мешает просмотреть и остальные ошибки; там мо% гут быть другие полезные сообщения об ошибках, но не всегда.
Если сборка продукта не прошла, смотрите на первую ошибку компилятора. Последующие сообщения заслуживают гораздо меньшего доверия.
Даже первое сообщение компилятора об ошибке может оказаться зага% дочным или вводящим в заблуждение; это зависит от качества компи% лятора (если смысл ошибки невозможно понять, попробуйте другой компилятор). Код стандартных шаблонов C++ может провоцировать
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Охотаm |
за ошибками |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
223Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
некоторые компиляторы на безудержный поток сообщений об ошиб% ках, содержащих таинственные заклинания.
Обычно синтаксическая ошибка находится на строке, указанной компи% лятором, но иногда – на предшествующей ей и делающей бессмыслен% ной следующую; компилятор замечает это и выражает неудовольствие.1
Пример 1: графическая утилита
Программа
Небольшая утилита с графическим интерфейсом.
Проблема
Программа была переработана для придания ей «современно% го вида» – новые значки и расположение элементов. Старый интерфейс предполагалось сохранить как опцию в настрой% ках. Во время модернизации все работало прекрасно почти до самого момента выпуска, когда кто%то попытался воспользо% ваться старым интерфейсом. Программа аварийно заверша% лась, когда начинало рисоваться окно, но прежде чем оно ото% бражалось полностью.
История
К счастью, эта проблема была возобновляемой. Программу запустили в отладчике и нашли место сбоя, которое оказалось где%то глубоко в библиотеке интерфейса пользователя в коде отображения графики.
Изучение вопроса навело на мысль, что используется недопус% тимая графика. Программа пыталась показать значок, нахо% дящийся по нулевому адресу памяти, т. е. аварийное оконча% ние вызывал нулевой указатель. По стеку вызовов мы опреде% лили, какое изображение нужно было показывать. Взглянув затем на каталог с графикой старой версии, мы обнаружили, что именно этого значка в нем и нет.
Очевидно, что сбой происходил в операции загрузки значка в конструкторе окна, возвращавшей нулевой указатель, кото% рый свидетельствовал о том, что загрузки значка не произош% ло. Но проверка возвращаемого значения отсутствовала – автор предположил, что графика всегда будет в положенном месте.
1C++ может иногда разыграть красивый фокус: предыдущая строка оказы% вается в другом файле! Если пропустить ; в конце объявления класса в за% головочном файле, то первая строка в файле реализации окажется бес% смысленной. Ошибка, о которой сообщает компилятор, оказывается весь%
ма загадочной.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
224m |
|||||
|
|
|
|
||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
. |
|
|
|
|
|
.c |
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
df |
|
|
n |
e |
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
Глава 9. Поиск ошибокClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Исправление должно быть двояким:
•Устроить проверку значений, возвращаемых всеми проце% дурами загрузки значков, чтобы они более элегантно обра% батывали случаи отсутствия графики.
•Поместить отсутствующую графику в нужные каталоги.
Время, потраченное на исправление
На изучение проблемы, исправление ошибки и проверку ис% правленного кода потребовалось несколько часов.
Полученные уроки
•Проверяйте значения, возвращаемые всеми функциями, даже если вам кажется, что в них не может быть сбоев.
•Тестируйте функции программы как можно раньше, осо% бенно редкие условия, которые будут возникать не часто.
Ошибки компоновки в целом гораздо более понятны. Редактор связей сообщит вам, что отсутствует некая функция или библиотека, так что лучше подсуетиться и найти ее (или написать). Иногда компоновщик жалуется на таинственные проблемы, связанные с таблицей виртуаль% ных методов C++; обычно это признак отсутствия деструктора или че% го%либо аналогичного.
Ошибки этапа исполнения
Ошибки этапа исполнения требуют более тонких действий. Если в про% грамме ошибка, это может означать, что содержащееся где%то в коде условие, которое вы считали выполненным, на самом деле таковым не является. Поиск ошибки состоит в последовательной проверке того, что вы считали истинным, до обнаружения места, где это условие не выполняется. Нужно создать модель реальной работы кода и сравнить ее с предполагавшейся вами работой. Единственный разумный путь – методически применять этот способ.
Отладка – это методичная работа, медленно сужающая кольцо вокруг мес& та нахождения ошибки. Не следует относиться к ней как к игре в угадайку.
Научный метод – это процесс, с помощью которого ученые получают точное представление об окружающем мире. Это сходно с тем, что пы% таемся сделать мы. Научный метод заключает в себе четыре этапа:
1.Наблюдение явления.
2.Формирование гипотезы, объясняющей явление.
3.Предсказание результатов других наблюдений на основе предло% женной гипотезы.
4.Проведение экспериментов, подтверждающих предсказания.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Охотаm |
за ошибками |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
225Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Несмотря на то, что мы пытаемся избавиться от феномена ошибки, а не построить его модель, нам необходимо понять суть ошибки, чтобы действительно устранить ее. Научный метод представляет собой хоро% шую основу для отладки, в чем вы убедитесь, изучив предлагаемые ниже действия.
Идентифицировать ошибку
Все начинается с обнаружения того, что программа делает не то, что нужно. Может быть, она аварийно завершается или выводит желтый треугольник вместо синего квадрата – вы видите непорядок и должны его выправить. Прежде всего нужно послать отчет об ошибке в базу данных (см. раздел «Система контроля ошибок» на стр. 205). Это осо% бенно важно, если вы находитесь в процессе отладки какой%то другой ошибки или у вас нет времени, чтобы сразу разобраться с ошибкой. Ре% гистрация ошибки гарантирует, что она не будет забыта. Не пытайтесь ограничиться мысленной отметкой о необходимости вернуться к про% блеме позже – вы обязательно забудете это сделать.
Прежде чем бросаться на поиски ошибки, вызвавшей обнаруженный вами сбой, определите сущность аномального поведения, с которым вы столкнулись. Опишите проблему как можно подробнее, ответив на следующие вопросы: зависит ли ошибка от времени? оказывают ли на нее влияние данные ввода, загруженность системы или состояние про% граммы? Если вы не разберетесь в сути ошибки до того, как начнете ее исправлять, вы просто станете модифицировать код, пока не исчезнут симптомы. Причина ошибки окажется замаскированной, и та же не% исправность проявится где%то в другом месте.
Работал ли код раньше? Поищите в своей системе контроля версий по% следнюю версию, работавшую без сбоев, и сравните тот код с нынешним.
Воспроизвести ошибку
Это нужно сделать в дополнение к описанию ошибки. Опишите набор действий, уверенно приводящий к возникновению данного сбоя. Если таких способов несколько, документируйте их все.
Первый шаг на пути установления места ошибки – это определение способа ее уверенного воспроизведения.
Хуже, если ошибку не удается воспроизвести. Необходимо расставить ловушки для сбора всевозможной информации на тот случай, если сбой возникнет снова. Если сбой возникает нерегулярно, тщательно накап% ливайте все сведения, получаемые в момент сбоя.
Определить место ошибки
Это серьезное дело. След взят; теперь нужно воспользоваться всеми по% лученными данными, чтобы найти зверя и точно установить, где он
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
226m |
|||||
|
|
|
|
||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
. |
|
|
|
|
|
.c |
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
df |
|
|
n |
e |
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
Глава 9. Поиск ошибокClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
залег. Легко сказать! Это процесс, в котором нужно отсеять все, что не имеет отношение к сбою или явно работает правильно – в духе Шерло% ка Холмса. По ходу дела выясняется потребность в дополнительной информации – чем больше ответов, тем больше возникает вопросов. Возможно, придется сочинить какие%то дополнительные тесты. Воз% можно, придется порыться в малоприятных потрохах кода.
Проанализируйте, что вам стало известно относительно сбоя. Не делая скороспелых выводов, составьте список подозреваемых участков кода. Попробуйте подметить какие%то закономерности событий, которые подскажут возможную причину. Если есть возможность, ведите учет входных и выходных данных, иллюстрирующих проблему.
Расследование хорошо начать с того места, где проявляет себя ошибка, хотя обычно она реально находится совсем в другом месте. Запомните: если отказ возникает в каком%то модуле, из этого необязательно следу% ет, что именно этот модуль во всем виноват. Определить место ава% рийного завершения легко; отладчик сообщит вам, в какой строке про% изошел сбой, значения всех переменных в тот момент и кто вызывал эту функцию. Если аварийного завершения нет, начните с того места, в котором программа ведет себя неправильно. Двигайтесь оттуда в об% ратном направлении, следуя порядку выполнения кода, и проверяйте, что в каждой точке код делает именно то, чего вы от него ждете.
Начните с известного места, например с точки аварийного завершения про& граммы. Затем двигайтесь в обратном направлении в сторону причины, вы& звавшей сбой.
Есть несколько стандартных стратегий поиска ошибок:
•Самое худшее – менять что%то произвольным образом и проверять, не исчезнет ли сбой. Это незрелый подход. (Хотя профессионал мо% жет попытаться придать ему наукообразный вид!)
•Гораздо лучше стратегия разделяй и властвуй. Допустим, вы су% зили область поиска до одной функции, в которой 20 шагов. После 10%го шага выведите промежуточный результат или установите контрольную точку и изучите ее в отладчике. Если значение пра% вильное, значит, ошибка находится в тех командах, которые лежат ниже; в противном случае она выше. Займитесь этой частью ко% манд и повторяйте операцию, пока не загоните ошибку в угол.
•Еще один способ – формальный прогон (dry run). Не рассчитывая, что интуиция поможет вам найти ошибку, поработайте сами вместо компьютера и выполните контрольную трассировку программы, вычисляя все промежуточные значения и конечный результат. Ес% ли ваш результат не совпадет с тем, который дает программа, ошиб% ка в коде – он не делает то, чего вы от него хотите. Конечно, это тре% бует времени, но зато эффективно, потому что доказывает, что ва%
ши предположения не верны.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
|
|
P |
|
|
|
|
|
NOW! |
o |
|
||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
w Click |
|
|
|
Охотаm |
за ошибками |
|||||
|
|
|
|
|||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
.c |
|
||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
227Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Уясните проблему
Когда вы найдете место, где таится ошибка, нужно разобраться в сути реальной проблемы. Если это простая синтаксическая ошибка, напри% мер = вместо == (уф!), последствия не слишком страшны. Если это более сложная семантическая проблема, убедитесь, что она вам понятна, как и все способы, которыми она может проявиться, и лишь потом дейст% вуйте дальше – возможно, вы обнаружили лишь часть проблемы.
Часто ошибка оказывается очень тонкой: код делает именно то, что должен и что вы предполагали, когда писали его! Проблема заключа% ется в ложных допущениях (помните, как они опасны?). Тот, кто пи% шет функцию, и тот, кто к ней обращается, вполне могут предполагать различное поведение функции отдельных особых случаях. Выполните обратную трассировку и точно разберитесь, в чем причина проблемы и нет ли других фрагментов кода, содержащих ту же ошибку.
Если вам показалось, что вы нашли причину ошибки, досконально исследуйте ее и убедитесь, что не ошиблись. Не принимайте безрассудно первую же ги& потезу.
Это важнейший принцип борьбы с ошибками. Иначе вы пополните число тех программистов, которые создают ошибок больше, чем устра% няют их во время отладки.
Создайте тест
Напишите контрольный пример, демонстрирующий ошибку. Вам стои% ло сделать это еще на этапе «Воспроизведите ее». Если вы не сделали этого тогда, то теперь точно настало время. Используя накопленные знания, сделайте тест достаточно строгим.
Исправьте ошибку
Теперь самое простое: нужно исправить эту чертову штуку! Здесь дей% ствительно не должно быть никаких трудностей: вы точно знаете, по% чему происходит сбой, и можете сами вызвать его появление. При та% ких данных исправление обычно оказывается плевым делом. Часто программисты считают, что исправлять ошибки трудно; это потому, что они пропускают первые два шага.
В следующем разделе мы более подробно рассмотрим, как исправлять ошибки.
Докажите, что вы ее исправили
Теперь вы знаете, зачем вам нужен контрольный пример. Прогоните его снова и докажите, что мир стал более совершенным. Этот контроль% ный пример можно добавить в комплект регрессивных тестов, чтобы гарантировать отсутствие возникновения той же ошибки в будущем.