- •Оглавление
- •Об авторе
- •Благодарности
- •Предисловие
- •Глава 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 |
|
|
|
40m |
|||||
|
|
|
|
||||||
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 |
|
|
|
|
|
|
Глава 1. Держим оборонуClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
значение.1 Обычно вывод таких предупреждений можно избиратель% но включать или отключать.
Если ваш код изобилует опасными конструкциями, такие предупреж% дения могут занять многие страницы. К сожалению, по этой причине очень часто отключают вывод предупреждений компилятором или просто не обращают на них внимания. Так поступать не следует.
Всегда включайте вывод предупреждений компилятором, и если ваш код генерирует предупреждения, немедленно исправьте его, чтобы та% ких сообщений больше не было. Нельзя успокаиваться, пока компиля% ция не станет проходить гладко при включенном выводе предупрежде% ний. Они существуют не зря. Даже когда вам кажется, что какое%то предупреждение несущественно, добейтесь его исчезновения, потому что в один прекрасный день из%за него вы не заметите того предупреж% дения, которое окажется действительно важным.
Предупреждения компилятора помогают выявить массу глупых ошибок. Все& гда включайте их вывод. Добейтесь того, чтобы ваш код компилировался молча.
Пользуйтесь средствами статического анализа
Предупреждения компилятора представляют собой результат частич% ного статического анализа кода – контроля кода, проводимого перед запуском программы.
Существует ряд самостоятельных инструментов статического анали% за, например lint или его более современные потомки для C и FxCop для сборок .NET. Вашей постоянной практикой должна стать провер% ка своего кода с помощью этих средств. Они обнаруживают гораздо больше ошибок, чем компилятор.
Применяйте безопасные структуры данных
Или, если это невозможно, пользуйтесь опасными структурами, но с осторожностью.
Вероятно, самым распространенным видом уязвимостей в программах является переполнение буфера. Оно возникает из%за небрежного при% менения структур данных фиксированного размера. Если ваш код за% писывает данные в буфер, не проверив предварительно его размер, то возникает опасность записи за концом буфера.
Это происходит с чрезвычайной легкостью, как демонстрирует сле% дующий фрагмент кода C++:
char *unsafe_copy(const char *source)
{
char *buffer = new char[10];
1Во многих языках (например, Java и 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 |
|
|
|
|
strcpy(buffer, source); return buffer;
}
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|||
|
|
X |
|
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
|
||
|
F |
|
|
|
|
|
|
t |
|
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
r |
||
P |
|
|
|
|
|
NOW! |
o |
|||
|
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|
|||
|
|
|
|
to |
|
|
|
|
|
|
41Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Если в источнике (source) больше 10 символов, то их копирование вый% дет за пределы памяти, выделенной под буфер (buffer). Результат мо% жет оказаться самым неожиданным. В лучшем случае произойдет раз% рушение данных, если окажется измененным содержимое какой%то другой структуры данных. В худшем – злоумышленник может вос% пользоваться этой ошибкой в программе и поместить в стек програм% мы исполняемый код, с помощью которого запустит собственную про% грамму и фактически завладеет компьютером. Ошибками такого рода систематически пользуются взломщики; это серьезная проблема.
Предотвратить появление таких уязвимостей нетрудно. Не пишите скверный код! Пользуйтесь более надежными структурами данных, которые не позволяют искажать программу, например управляемыми буферами типа класса string в C++. Либо применяйте к небезопасным типам данных только безопасные операции. Приведенный выше код C++ можно защитить, заменив strcpy на strncpy, которая копирует строку ограниченной длины:
char *safer_copy(const char *source)
{
char *buffer = new char[10]; strncpy(buffer, source, 10); return buffer;
}
Проверяйте все возвращаемые значения
Если функция возвращает значение, то делает это не зря. Проверяйте возвращаемое значение. Если это код ошибки, нужно ее обработать. Не допускайте появления в программе незамеченных ошибок; в итоге поведение программы может стать непредсказуемым.
Это относится как к определенным пользователям, так и к библиотеч% ным функциям. Чаще всего коварные ошибки возникают тогда, когда программист не проверяет возвращаемые значения. Не забывайте, что иногда функции сообщают об ошибках с помощью иного механизма (например, при помощи стандартной переменной errno библиотеки C). Всегда перехватывайте и обрабатывайте соответствующие исключе% ния на соответствующем уровне.
Аккуратно обращайтесь с памятью (и другими ценными ресурсами)
Будьте скрупулезны и освобождайте все ресурсы, которые захватывае% те во время выполнения. Чаще всего имеется в виду оперативная па% мять, но это не единственный ресурс. К другим видам ценных ресурсов,
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
C |
|
E |
|
|||
|
|
X |
|
|
|
|
|||
|
- |
|
|
|
|
|
d |
||
|
F |
|
|
|
|
|
|
t |
|
|
D |
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
r |
|
P |
|
|
|
|
|
NOW! |
o |
||
|
|
|
|
|
|
||||
|
|
|
|
|
BUY |
|
|||
|
|
|
|
to |
|
|
|
|
|
w Click |
|
|
|
42m |
|||||
|
|
|
|
||||||
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 |
|
|
|
|
|
|
Глава 1. Держим оборонуClick |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
которые нужно беречь, относятся файлы и блокировки потоков. Рас% поряжайтесь своим добром экономно.
Не пренебрегайте тем, чтобы самостоятельно закрыть файлы или осво% бодить память, не рассчитывая, что это сделает ОС по завершении про% граммы. Неизвестно, сколь долго еще будет выполняться ваш код, по% жирая дескрипторы файлов и память. Нельзя даже быть уверенным, что ОС правильно освободит ваши ресурсы – не все системы делают это.
Существует мнение, что не стоит заниматься освобождением памяти, пока вы не убедитесь, что программа работает. Не верьте этому. Это крайне опасная практика. Она приводит к многочисленным ошибкам работы с памятью; вы обязательно пропустите какие%то места, где нужно освободить память.
Берегите все ограниченные ресурсы. Тщательно организуйте их захват и осво& бождение.
В Java и .NET есть сборщик мусора, который сделает вместо вас всю эту скучную приборку, чтобы вы могли «забыть» об освобождении ре% сурсов. Можно мусорить на пол, потому что на этапе исполнения за ва% ми будут периодически подметать. Это замечательно удобно, но у вас не должно возникнуть ложного чувства безопасности. Думать самому все равно нужно. Вы должны явно уничтожить ссылки на объекты, которые вам больше не нужны, иначе они не будут убраны; не делайте ошибки, сохраняя ссылки на объекты. Кроме того, менее изощренные сборщики мусора могут быть введены в заблуждение циклическими ссылками (например, A ссылается на B, B ссылается на A, но тот и дру% гой никому не нужны). В этом случае объекты могут никогда не по% пасть в мусор, что ведет к скрытой утечке памяти.
Инициализируйте все переменные там, где вы их объявили
Это проблема ясности. Смысл каждой переменной становится ясен, ес% ли вы инициализируете ее. Опасно полагаться на эмпирические пра% вила типа: «Раз я ее не инициализировал, значит, ее начальное значе# ние мне неважно». Код со временем развивается. Отсутствие началь% ного значения на каком%то этапе может превратиться в проблему.
C и 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 |
|
|
|
|
|
|
43Click |
|
|
|
|
|
m |
||||
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
.c |
|
||
|
. |
|
|
|
|
|
|
|||
|
|
p |
|
|
|
|
g |
|
|
|
|
|
|
df |
|
|
n |
e |
|
||
|
|
|
|
-x cha |
|
|
|
|
Более защищенные языки (такие как Java и C#) обходят эту опасность путем определения начальных значений для всех переменных. Тем не менее полезно инициализировать переменные при их объявлении, так как это облегчает понимание кода.
Объявляйте переменные как можно позже
Благодаря этому переменная будет располагаться ближе к месту сво% его использования и не станет мешаться в других частях кода. Кроме того, понятнее станет код, в котором участвует эта переменная. Вам не придется рыскать, выясняя тип и значение переменной: расположен% ное рядом объявление сделает их очевидными.
Не пользуйтесь повторно одной и той же временной переменной в раз% ных местах, даже если они логически независимы. В противном случае вы чрезвычайно осложните дальнейшую модернизацию кода. Каждый раз создавайте новую переменную, а компилятор сам разберется, мож% но ли оптимизировать такой код.
Пользуйтесь стандартными средствами языка
C и C++ в этом отношении представляют собой кошмар. Их специфи% кации существуют во многих вариантах, а поведение в наименее ясных ситуациях не определено и оставлено на усмотрение конкретных реа% лизаций. На сегодняшний день существует множество компиляторов, обладающих тонкими различиями. В целом они совместимы между со% бой, но оставляют вам достаточно возможностей свернуть себе шею.
Четко определите, какой версией языка вы пользуетесь. Если только ваш проект не оставляет иного выбора (и причины должны быть доста% точно вескими), не пользуйтесь индивидуальными особенностями ком% пилятора и нестандартными расширениями языка. Если в языке есть неопределенная область, не полагайтесь на то, как ведет себя в ней ваш конкретный компилятор (например, если ваш компилятор C рассмат% ривает char как величину со знаком, то другие компиляторы могут не делать этого). В противном случае код становится очень неустойчи% вым. А если вы перейдете на новую версию компилятора? А если в ко% манде появится новый программист, не знакомый с вашими расшире% ниями? Полагаясь на необычные свойства конкретного компилятора, вы создаете источник труднообнаруживаемых ошибок, которые мо% гут появиться в будущем.
Пользуйтесь хорошими средствами регистрации диагностических сообщений
Когда пишут новый код, то часто включают в него много операторов вывода диагностики, чтобы разобраться в происходящем в программе. Следует ли удалить их в конце работы? Сохранив их, вы облегчите