Средства отладки
Отладчики – не единственные средства нахождения ошибок. Самые различные программы помогают нам обрабатывать объемистый вывод для того, чтобы отыскивать интересующие участки, находить аномалии и представлять выходные данные в наиболее простой и понятной форме. Многие из таких программ входят в стандартный набор утилит, другие пишутся специально, чтобы обнаружить конкретную ошибку или проанализировать определенную программу.
В этой главе мы опишем простую программу strings, очень полезную для просмотра файлов, состоящих в основном из непечатаемых символов, например исполняемых файлов или таинственных двоичных форматов, столь любимых некоторыми текстовыми процессорами. В таких файлах часто спрятана полезная информация, например текст документа, сообщения об ошибках, недокументированные опции программы, имена файлов и каталогов или имена функций, которые могут вызываться программой.
Программа strings полезна и для нахождения текста в других двоичных файлах. Файлы с изображениями часто содержат ASCII-строки, сообщающие, какая программа создала этот файл, а сжатые файлы и архивы (например, zip-файлы) могут содержать имена файлов: strings обнаружит и их.
Unix-системы обычно уже содержат реализацию программы strings, хоть она и отличается от той, которую запрограммируем мы. Unix-версия в случае, если обрабатываемый файл – программа, просматривает только сегменты кода и данных, игнорируя таблицу символов. Ключ – а заставляет ее читать весь файл.
В сущности, strings извлекает ASCII-строку из двоичного файла, чтобы ее можно было прочитать или обработать с помощью другой программы. Если в тексте сообщения об ошибке не говорится, какая именно программа выдала данное сообщение, то узнать это, не говоря уж о том, почему именно она его выдала, будет довольно сложно. В этом случае установить источник можно поиском в подозрительных каталогах; этот поиск выполняется с помощью такой команды:
% strings *.ехе *.dll | grep 'mystery message'
Функция strings читает файл и печатает каждую последовательность из как минимум MINLEN = 6 печатных символов.
Форматная строка %. *s в функции printf берет длину строки из следующего аргумента (i), потому что buf не завершается нулем.
Цикл do-whi|le находит и печатает каждую строку, заканчивая работу при обнаружении EOF. Проверка конца файла после тела цикла позволяет функции getc и циклу по строке иметь одинаковое условие завершения, а также с\ помощью единственного обращения к printf обрабатывать конец строки, конец файла и слишком длинные строки.
Стандартный внешний цикл с проверкой при входе или единственный цикл с getc и более сложным телом заставил бы использовать printf дважды. Эта функция сначала так и работала, но потом мы нашли ошибку в операторе printf. Исправив в одном месте, мы забыли исправить ее в двух других. ("А не делал ли я ту же самую ошибку где-нибудь еще?") Здесь нам стало ясно, что программу нужно переписать, чтобы дублирующегося кода было меньше; так появился цикл do-while.