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

Функция errExitEN() представляет собой практически то же самое, что и errExit(), за исключением того, что вместо сообщения об ошибке, характерного текущему значению errno, она выводит текст, соответствующий номеру ошибки (отсюда и суффикс EN), заданному в аргументе errnum.

В основном функция errExitEN() применяется в программах, использующих API потоков стандарта POSIX. В отличие от традиционных системных вызовов UNIX, возвращающих при возникновении ошибки –1, функции потоков стандарта POSIX позволяют определить тип ошибки по ее номеру, возвращенному в качестве результата их выполнения (то есть в errno, как правило, помещается положительный номер типа). (В случае успеха функции потоков стандарта POSIX возвращают 0.)

Определить типы ошибок из функции потоков стандарта POSIX можно с помощью следующего кода:

errno = pthread_create(&thread, NULL, func, &arg);

if (errno!= 0)

errExit("pthread_create");

Но такой подход неэффективен, поскольку в программе, выполняемой в нескольких потоках, errno определяется в качестве макроса. Этот макрос расширяется в вызов функции, возвращающий левостороннее выражение (lvalue). Соответственно, каждое использование errno приводит к вызову функции. Функция errExitEN() позволяет создавать более эффективный эквивалент показанного выше кода:

int s;

s = pthread_create(&thread, NULL, func, &arg);

if (s!= 0)

errExitEN(s, "pthread_create");

Согласно терминологии языка C левостороннее выражение (lvalue) — это выражение, ссылающееся на область хранилища3. Наиболее характерным его примером является идентификатор для переменной. Некоторые операторы также выдают такие выражения. Например, если p является указателем на область хранилища, то *p является левосторонним выражением. Согласно API потоков стандарта POSIX, errno переопределяется в функцию, возвращающую указатель на область хранилища, относящуюся к отдельному потоку (см. раздел 31.3).

Для определения других типов ошибок используются функции fatal(), usageErr() и cmdLineErr().

#include "tlpi_hdr.h"

void fatal(const char *format…);

void usageErr(const char *format…);

void cmdLineErr(const char *format…);

Функция fatal() применяется для определения типа ошибок общего характера, включая ошибки библиотечных функций, не устанавливающих значения для errno. У нее точно такой же список аргументов, что и у функции printf(), за исключением того, что к строке вывода автоматически добавляется символ конца строки. Она выдает отформатированный вывод на стандартное устройство вывода ошибки, а затем завершает выполнение программы с помощью errExit().

Функция usageErr() предназначена для определения типов ошибок при использовании аргументов командной строки. Она принимает список аргументов в стиле printf() и выводит строку Usage:, за которой следует отформатированный вывод на стандартное устройство вывода ошибки, после чего она завершает выполнение программы путем вызова exit(). (Некоторые примеры программ в этой книге предоставляют свою собственную расширенную версию функции usageErr() под именем usageError().)

Функция cmdLineErr() похожа на usageErr(), но предназначена для определения типов ошибок в переданных программе аргументах командной строки.

Реализации функций определения типов ошибок показаны в листинге 3.3.

Листинг 3.3. Функции обработки ошибок, используемые всеми программами

lib/error_functions.c

#include <stdarg.h>

#include "error_functions.h"

#include "tlpi_hdr.h"

#include "ename.c.inc" /* Определяет ename и MAX_ENAME */

#ifdef __GNUC__

__attribute__ ((__noreturn__))

#endif

static void

terminate(Boolean useExit3)

{

char *s;

/* Сохраняет дамп ядра, если переменная среды EF_DUMPCORE определена

и содержит непустую строку; в противном случае вызывает exit(3)

или _exit(2), в зависимости от значения 'useExit3'. */

s = getenv("EF_DUMPCORE");

if (s!= NULL && *s!= '\0')

abort();

else if (useExit3)

exit(EXIT_FAILURE);

else

_exit(EXIT_FAILURE);

}

static void

outputError(Boolean useErr, int err, Boolean flushStdout,

const char *format, va_list ap)

{

#define BUF_SIZE 500

char buf[BUF_SIZE], userMsg[BUF_SIZE], errText[BUF_SIZE];

vsnprintf(userMsg, BUF_SIZE, format, ap);

if (useErr)