
- •Оглавление
- •Об авторе
- •Благодарности
- •Предисловие
- •Глава 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. За гранью возможного
- •Вопросы для размышления
- •Вопросы личного характера
- •Библиография
- •Алфавитный указатель
Какую работу нужно написать?
36 |
Глава 1. Держим оборону |
Технологии защитного программирования
Но хватит общих слов. Что все это значит для программистов на прак% тике?
Защитное программирование предполагает соблюдение ряда разум% ных правил. Обычно, когда заходит речь о защитном программирова% нии, людям приходит в голову использовать операторы контроля, и это правильно. Мы поговорим о них позже. Но существует также мас% са простых приемов программирования, которые неизмеримо повысят надежность вашего кода.
Несмотря на свою очевидность, они часто игнорируются, откуда и про% истекает низкое качество большей части существующего программно% го обеспечения. Большей безопасности и надежной разработки можно достичь на удивление легко, если только программисты проявят бди% тельность и компетентность.
Несколько последующих страниц посвящены перечислению правил защитного программирования. Сначала мы нарисуем общую картину, рассмотрев защитные приемы, процессы и процедуры верхнего уров% ня. Затем займемся деталями и более пристально рассмотрим отдель% ные операторы кода. Некоторые из этих защитных приемов специфич% ны для применяемых языков программирования. И это естественно: если язык допускает какие%то вредоносные действия, то именно от них и нужно защищаться.
Читая этот список, проверьте себя. Многие ли из этих правил вы со% блюдаете в своей практике? Какие из них вы теперь готовы принять на вооружение?
Выберите хороший стиль кодирования и пользуйтесь крепкой архитектурой
Значительной части ошибок можно избежать, придерживаясь доброт% ного стиля кодирования. Это правило согласуется с остальными глава% ми данной части. Такие простые вещи, как выбор осмысленных имен переменных и разумная расстановка скобок, делают код понятнее и уменьшают шансы пропустить ошибку.
Точно так же очень важно изучить проект в целом, прежде чем погру% жаться в написание кода. «Лучшая документация компьютерной про% граммы – это ее четкая структура». (Kernighan Plaugher 78) Если вы начнете с того, что реализуете понятные API, определите логичную структуру системы и четкие роли и задачи компонент, то избавитесь от возможной головной боли в будущем.
Пишите код без спешки
Сплошь и рядом программы пишут сломя голову. Программист быст% ренько ляпает функцию, пропускает ее через компилятор для провер%

Технологии защитного программирования |
37 |
ки синтаксиса, запускает, чтобы убедиться в ее работоспособности, и переходит к очередной задаче. Такой подход чреват опасными по% следствиями.
Правило: необходимо обдумывать каждую новую строку. Какие ошиб% ки могут в ней возникнуть? Все ли возможные повороты логики вы рассмотрели? Медленное и методичное программирование может по% казаться скучным, но оно действительно сокращает количество оши% бок в программе.
Чем больше спешки, тем меньше скорость. Всегда думайте, что вы собирае& тесь ввести с клавиатуры.
Пример ловушки, которая поджидает спешащих программистов, пи% шущих на языках семейства C, – это ошибочный ввод = вместо ==. Первый оператор присваивает значение переменной, а второй прове% ряет равенство. Недружественный компилятор (или с отключенным выводом предупреждений) не покажет вам, что программа будет вы% полняться не так, как вам хотелось.
Не бросайтесь вперед, пока не выполните все задачи, необходимые для завершения работы с каким%то разделом кода. Например, если вы со% бираетесь сначала написать основной код, а потом заняться проверкой
иобработкой ошибок, вы должны твердо решить, что сделаете и то,
идругое. Никогда не откладывайте на будущее проверку ошибок ради того, чтобы написать основной код еще нескольких разделов. Ваше на% мерение вернуться к обработке ошибок позже может быть вполне ис% кренним, но «позже» может превратиться в «гораздо позже», когда вы в значительной мере забудете контекст, что в результате потребует еще большего труда и времени. (И разумеется, к тому моменту вам бу% дет поставлен какой%нибудь нереальный срок завершения работы.)
Дисциплинированность – это привычка, которую надо усвоить и укреп% лять. Всякий раз, когда вы откладываете выполнение необходимого дела, вы увеличиваете вероятность того, что не выполните его и в буду% щем. Сделайте это сейчас, не дожидаясь того дня, когда в Сахаре прой% дет дождь. На самом деле, для того чтобы сделать это потом, а не сей% час, требуется обладать еще большей дисциплинированностью!
Не верьте никому
Мама говорила вам, чтобы вы не вступали в разговор с незнакомыми людьми? К сожалению, разработка хороших программ требует еще больше цинизма и еще меньше доверия к человеческой натуре. Даже добропорядочные пользователи могут вызвать проблемы у вашей про% граммы; защищаясь, нельзя доверять никому.
У вас могут возникнуть проблемы по следующим причинам:
•Обычный пользователь случайно введет в программу неверные данные или воспользуется ею некорректно.

38 |
Глава 1. Держим оборону |
•Злоумышленник сознательно попытается заставить программу ве% сти себя некорректно.
•Клиентский код вызовет вашу функцию, неправильно передав ей параметры или задав им недопустимые значения.
•Операционная среда не сможет предоставить программе необходи% мый сервер.
•Внешние библиотеки окажутся некорректными и не выполнят те контракты по интерфейсам, на которые вы полагались.
А может быть, вы сами сделаете глупую ошибку в какой%то функции или забудете, как работает код, написанный вами три года назад, и не% правильно воспользуетесь им. Не рассчитывайте, что все будет хорошо и весь код будет работать корректно. Ставьте проверки везде, где толь% ко можно. Все время ищите слабые точки и помещайте в них дополни% тельные средства защиты.
Не верьте никому. Кто угодно, включая вас самих, может сделать ошибки в логике вашей программы. Ко всем входным и выходным данным относитесь с подозрением, пока не проверите, что они допустимы.
Стремитесь к ясности, а не к краткости
Когда встает выбор между кратким (но непонятным) и ясным (но скуч% ным) кодом, делайте его в пользу того кода, смысл которого понятен, даже если он менее элегантен. Например, сложные арифметические выражения разбивайте на последовательность отдельных операторов, логика которых понятнее.
Подумайте о тех, кто будет читать ваш код. Возможно, его будет сопро% вождать менее опытный кодировщик, и если он не разберется в логике, то может сделать ошибки. Сложные конструкции или оригинальные фокусы с языком могут свидетельствовать о ваших энциклопедиче% ских знаниях в области приоритетов операторов, но сильно ослабят возможность сопровождения кода. Будьте проще.
Код, который нельзя сопровождать, не может быть безопасным. В от% дельных случаях чрезмерно сложные выражения приводят к генера% ции компилятором некорректного кода – так часто обнаруживаются ошибки в оптимизации, проводимой компилятором.
Простота – это достоинство. Не усложняйте код сверх необходимости.
Не позволяйте никому лезть туда, где ему нечего делать
То, что является внутренним делом, должно оставаться внутри. Ваши личные вещи должны храниться под замком. Не нужно демонстриро% вать свое грязное белье на публике. Несмотря на любые ваши просьбы, стоит только отвернуться, и люди начнут ковыряться в ваших дан%

Технологии защитного программирования |
39 |
Когда приступать?
Когда начинать программировать в защитном стиле? После того как выявятся неполадки? Или когда попадется непонятный код, написанный кем%то другим?
Нет, технологии защитного программирования нужно применять постоянно. Они должны войти в привычку. Опытные программи% сты знают это по своему опыту; они достаточно часто обжигались, и теперь размещают в программах разумные средства защиты.
Защитные средства гораздо проще применять с самого начала написания кода, нежели пытаться вмонтировать в уже сущест% вующий. Если пытаться втиснуть их в код на поздних стадиях работы с ним, трудно ничего не упустить и быть точным. Если вы начинаете добавлять защитный код уже после того, как воз% никли неполадки, то фактически занимаетесь отладкой, т. е. ре% агируете на события, а не предупреждаете их.
Тем не менее в процессе отладки или добавления новых функций обнаруживаются условия, которые желательно проверять. Вот тогда и полезно добавить защитный код.
ных, если вы оставите для этого малейшую возможность, и станут вы% зывать «внутренние» функции по своему разумению. Не позволяйте им этого делать.
•В объектно%ориентированных языках доступ к внутренним данным класса запрещается путем объявления его закрытым. В C++ можно воспользоваться идиомой Чеширского кота (или pimpl) – стандарт% ным приемом, употребляемым для выведения внутренней структу% ры класса из его открытого файла заголовка. (Meyers 97)
•В процедурных языках также можно воспользоваться идеями объ% ектно%ориентированной упаковки, заключив закрытые данные внут% ри непрозрачных типов и обеспечив корректные операции над ними.
•Дайте всем переменным минимально необходимую область видимо% сти; не делайте их глобальными, если в этом нет необходимости. Ес% ли их можно сделать локальными для функции, не объявляйте их на уровне файла. Если их можно сделать локальными для цикла, не объявляйте их на уровне функции.
Включайте вывод всех предупреждений при компиляции
Большинство компиляторов выдает массу сообщений об ошибках, когда их что%то не устраивает в коде. Они также выводят различные предупре# ждения, если им кажется, что в коде может быть ошибка, например в C или C++ использование переменной до того, как ей присваивается