Брайан Керниган - UNIX — универсальная среда программирования
- Название:UNIX — универсальная среда программирования
- Автор:
- Жанр:
- Издательство:Финансы и статистика
- Год:1992
- Город:Москва
- ISBN:5-289-00253-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Брайан Керниган - UNIX — универсальная среда программирования краткое содержание
В книге американских авторов — разработчиков операционной системы UNIX — блестяще решена проблема автоматизации деятельности программиста, системной поддержки его творчества, выходящей за рамки языков программирования. Профессионалам открыт богатый "встроенный" арсенал системы UNIX. Многочисленными примерами иллюстрировано использование языка управления заданиями shell.
Для программистов-пользователей операционной системы UNIX.
UNIX — универсальная среда программирования - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Используйте средства манипуляций файлами, встроенные в exec
shell
(см. справочное руководство по sh(1)
), чтобы фиксировать обращения к system
с терминала ttyin
.
Если вы забыли определить источник ввода для p
, то программа "молча" ожидает ввода с терминала. Стоит ли искать эту возможную ошибку? Если да, то как? Подсказка: isatty(3)
.
6.5 Пример: pick
Версия pick
из гл. 5, несомненно, увеличивает возможности shell
. Версия на Си, приведенная ниже, в чем-то отличается от рассмотренной в гл. 5. Если эта версия имеет аргументы, то они обрабатываются так же, как и ранее, но если определен единственный аргумент '-'
, pick
обрабатывает свой стандартный входной поток.
Почему бы в отсутствие аргументов просто не читать стандартный входной поток? Рассмотрим вторую версию команды zap
из разд. 5.6:
kill $SIG `pick\`ps-ag | egrep "$*"\` | awk '{print $1}'`
Что происходит, если шаблон egrep
ни с чем не совпадает? В этом случае pick
не имеет аргументов и читает свой стандартный входной поток; команда zap
терпит неудачу загадочным образом. Требование явного аргумента простой способ устранить неоднозначность, и соглашение о '-'
в cat
и других программах показывает, как его определить.
/* pick: offer choice on each argument */
#include
char *progname; /* program name for error message */
main(argc, argv)
int argc;
char *argv[];
{
int i;
char buf[BUFSIZ];
progname = argv[0];
if (argc == 2 && strcmp(argv[1], "-") == 0) /* pick - */
while (fgets(buf, sizeof buf, stdin) != NULL) {
buf[strlen(buf)-1] = '\0'; /* drop newline */
pick(buf);
}
else
for (i = 1; i < argc; i++)
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
текущего справочника. Вы также можете заставить программу сделать дамп памяти, напечатав ctl-\ , если она выполняется как фоновая, или с помощью команды kill -3
, если она основная.
Существуют две программы adb
и sdb
, назначение которых разбираться в "посмертной выдаче". Подобно большинству отладчиков, они "хитроумны", сложны и без них трудно обойтись. Программа adb
есть в седьмой версии системы, a sdb
доступна в более поздних версиях.
Из-за ограниченного объема книги мы лишь частично покажем вам применение каждой программы, а именно распечатаем содержимое стека, т.е. выведем функцию, выполнявшуюся при аварийном завершении программы, функцию, которая ее вызывала, и т.д. Первая функция, указанная в распечатке стека, это то место, где находилась программа, когда она была аварийно завершена.
Чтобы получить распечатку стека с помощью adb
, нужно ввести команду $C :
$ adb pick core
Вызывает adb
$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
. (Распечатка стека другая, так как это сделано на машине VAX-11/750, на которой стандартная библиотека ввода вывода реализована иначе.) И если мы взглянем на вызов fprintf
в неправильной версии pick
, то обнаружим некорректность:
fprintf("%s?", s);
Здесь нет stderr
, так что строка формата используется как ссылка к FILE
, и, конечно, получается хаос.
Мы показали вам типичную ошибку, которая является скорее результатом просмотра, а не неправильного программирования. Искать подобные ошибки при вызове функции с неверными аргументами можно также с помощью верифицирующей программы для Си lint(1)
. Эта программа рассматривает Си-программы с точки зрения наличия ошибок, аспектов переносимости и сомнительных конструкций. Если мы запустим lint
с файлом pick.с
, ошибка идентифицируется:
Интервал:
Закладка: