pick(argv[i]);
exit(0);
}
pick(s) /* offer choice of s */
char *s;
{
fprintf(stderr, "%s? ", s);
if (ttyin() == 'y')
printf("%s\n", s);
}
Версия pick
Если есть pick
rm -i?6.6 Об ошибках и отладке
Если вы писали программы ранее, вам знакомо понятие ошибки. Однако важно не только создавать программы, свободные от ошибок, но и заботиться о том, чтобы ваш проект был прост, тщательно реализован и сохранял свою "чистоту" в процессе модификации.
В UNIX много инструментов, которые помогут вам находить ошибки, хотя ни один из них не является действительно первоклассным. Для того чтобы продемонстрировать их, нам нужна ошибка; все же программы в этой книге совершенны. Поэтому мы "создадим" типичную ошибку. Рассмотрим приведенную выше функцию pick
pick(s) /* offer choice of s */
char *s;
{
fprintf("%s? ", s);
if (ttyin() == 'y')
printf("%s\n", s);
}
Что произойдет, если мы откомпилируем и запустим ее?
$ сс pick.с -о pick
$ pick *.с
Ошибка при обращении к памяти - сделан дамп
$
Сообщение "Ошибка при обращении к памяти" свидетельствует о том, что ваша программа пыталась работать с недозволенной областью памяти. Обычно в таком случае указатель содержит неправильное значение. "Ошибка адресации шины" другое диагностическое сообщение со сходным значением, часто обусловленное просмотром бесконечной строки. "Сделан дамп памяти" означает, что ядро сохранило состояние вашей выполняемой программы в файле core
kill -3, если она основная.Существуют две программы adb
sdb, назначение которых разбираться в "посмертной выдаче". Подобно большинству отладчиков, они "хитроумны", сложны и без них трудно обойтись. Программа adb есть в седьмой версии системы, a sdb доступна в более поздних версиях.Из-за ограниченного объема книги мы лишь частично покажем вам применение каждой программы, а именно распечатаем содержимое стека, т.е. выведем функцию, выполнявшуюся при аварийном завершении программы, функцию, которая ее вызывала, и т.д. Первая функция, указанная в распечатке стека, это то место, где находилась программа, когда она была аварийно завершена.
Чтобы получить распечатку стека с помощью adb
$ adb pick core
$C
~_strout(0175722,011,0,011200)
adjust: 0
fillch: 060542
__doprnt(0177345,0176176,011200)
~fprintf(011200,0177345)
iop: 01120
fmt: 0177345
args: 0
~pick(0177345)
s: 0177345
~main(035,0177234)
argc: 035
argv: 0177234
i: 01
buf: 0
ctl-d
$
Здесь речь идет о том, что main
pick, которая вызвала fprintf, а она в свою очередь вызвала __doprnt, вызвавшую _strout. Так как __doprnt не упомянута где-либо в pick.с, ошибка должна быть где-то в fprintf или выше. (Строки после каждой функции в распечатке показывают значения локальных переменных. $С подавляет данную информацию так же, как сама $С делает это в некоторых версиях adb.) Попытаемся теперь сделать то же самое с помощью sdb:$ sdb pick core
Предупреждение: 'a.out не компилируется с -g
lseek: address 0xa64
*t
lseek()
fprintf(6154,2147479154)
pick(2147479154)
main(30,2147478988,2147479112)
*q
$
Информация размещена по-иному, но есть общая основа: fprintf
fprintf в неправильной версии pick, то обнаружим некорректность:fprintf("%s?", s);
Здесь нет stderr
FILE, и, конечно, получается хаос.