Выбрать главу

Некоторые системные вызовы (например, getpriority()) могут вполне законно возвращать при успешном завершении значение –1. Чтобы определить, не возникла ли при таких вызовах ошибка, перед самим вызовом нужно установить errno в 0 и проверить ее значение после вызова. Если вызов возвращает –1, а errno имеет ненулевое значение, значит, произошла ошибка. (Это же правило применимо к некоторым библиотечным функциям.)

Общая линия поведения после неудачного системного вызова заключается в выводе сообщения об ошибке на основе значения переменной errno. Для этой цели предоставляются библиотечные функции perror() и strerror().

Функция perror() выводит строку, указываемую с помощью аргумента msg. За строкой следует сообщение, соответствующее текущему значению переменной errno.

#include <stdio.h>

void perror(const char *msg);

Простой способ обработки ошибок из системных вызовов будет выглядеть следующим образом:

fd = open(pathname, flags, mode);

if (fd == -1) {

perror("open");

exit(EXIT_FAILURE);

}

Функция strerror() возвращает строку описания ошибки, соответствующую номеру ошибки, который задан в ее аргументе errnum.

#include <string.h>

char *strerror(int errnum);

Возвращает указатель на строку с описанием ошибки, соответствующую значению errnum

Строка, возвращенная strerror(), может быть размещена статически, что означает, что она может быть переписана последующими вызовами strerror().

Если в errnum указан нераспознаваемый номер ошибки, то strerror() возвращает строку вида Unknown error nnn (неизвестная ошибка с таким-то номером). В некоторых других реализациях strerror() в таких случаях возвращает значение NULL.

Поскольку функции perror() и strerror() чувствительны к настройкам локали (см. раздел 10.4), описания ошибок выводятся на языке локали.

Обработка ошибок из библиотечных функций

Различные библиотечные функции для обозначения ошибок возвращают разные типы данных и разные значения. (По каждой функции нужно обращаться к странице руководства.) В рамках этого раздела библиотечные функции могут быть разбиты на несколько категорий.

• Некоторые библиотечные функции возвращают информацию об ошибке точно таким же образом, что и системные вызовы: возвращают значение –1, а значение переменной errno указывает на конкретную ошибку. Примером такой функции может послужить remove(), удаляющая файл (используя системный вызов unlink()) или каталог (используя системный вызов rmdir()). Ошибки из этих функций могут определяться точно так же, как и ошибки из системных вызовов.

• Некоторые библиотечные функции возвращают при ошибке значение, отличное от –1, но все-таки устанавливают значение для переменной errno, чтобы указать на конкретные условия возникновения ошибки. Например, функция fopen() в случае ошибки возвращает нулевой указатель и устанавливает для переменной errno значение в зависимости от того, какой из положенных в основу ее работы системных вызовов завершился неудачно. Для определения типа таких ошибок могут применяться функции perror() и strerror().

• Другие библиотечные функции вообще не используют переменную errno. Метод определения наличия и причин ошибок зависит от конкретной функции и задокументирован на посвященной ей странице руководства. Для таких функций применение errno, perror() или strerror() с целью определения типа ошибок будет неприемлемо.

3.5. Пояснения по поводу примеров программ, приводимых в книге

В этом разделе будут рассмотрены различные соглашения и характерные особенности, которые обычно применяются к примерам программ, приводимым в книге.

3.5.1. Ключи и аргументы командной строки

Многие примеры программ в книге основаны на использовании ключей и аргументов командной строки, определяющих их поведение.

Традиционные ключи командной строки UNIX состоят из начального дефиса, буквы, идентифицирующей ключ, и необязательного аргумента. (Утилиты GNU предоставляют расширенный синтаксис ключей, состоящий из двух начальных дефисов, за которыми следует строка, идентифицирующая ключ, и необязательный аргумент.) Для анализа этих ключей используется стандартная библиотечная функция getopt().

Каждый из наших примеров, где есть неочевидный синтаксис командной строки, снабжен простым вспомогательным средством для пользователя. При вызове с ключом — help программа выводит сообщение о порядке своей работы, показывая синтаксис для ключей и аргументов командной строки.