команды 'gcc — Wall', жалующиеся, что "control reaches end of non-void
function", то есть что управление достигло конца функции, которая
должна вернуть значение, если мы используем следующие функции для
прекращения выполнения main() или какой-нибудь другой функции,
которая должна вернуть значение определенного типа (не void) */
#define NORETURN __attribute__ ((__noreturn__))
#else
#define NORETURN
#endif
void errExit(const char *format…) NORETURN;
void err_exit(const char *format…) NORETURN;
void errExitEN(int errnum, const char *format…) NORETURN;
void fatal(const char *format…) NORETURN;
void usageErr(const char *format…) NORETURN;
void cmdLineErr(const char *format…) NORETURN;
#endif
lib/error_functions.h
Для определения типа ошибок системных вызовов и библиотечных функций используются функции errMsg(), errExit(), err_exit() и errExitEN().
#include "tlpi_hdr.h"
void errMsg(const char *
void errExit(const char *
void err_exit(const char *
void errExitEN(int
Функция errMsg() выводит сообщение на стандартное устройство вывода ошибки. Ее список аргументов совпадает со списком для функции printf(), за исключением того, что в строку вывода автоматически добавляется символ конца строки. Функция errMsg() выводит текст ошибки, соответствующий текущему значению переменной errno. Этот текст состоит из названия ошибки, например EPERM, дополненного описанием ошибки в том виде, в котором его возвращает функция strerror(), а затем следует вывод, отформатированный согласно переданным агрументам.
По своему действию функция errExit() похожа на errMsg(), но она также прекращает выполнение программы, либо вызвав функцию exit(), либо, если переменная среды EF_DUMPCORE содержит непустое строковое значение, вызвав функцию abort(), чтобы создать файл дампа ядра для его использования отладчиком. (Файлы дампа ядра будут рассмотрены в разделе 22.1.)
Функция err_exit() похожа на errExit(), но имеет два отличия:
• не сбрасывает стандартный вывод перед выводом в него сообщения об ошибке;
• завершает процесс путем вызова _exit(), а не exit(). Это приводит к тому, что процесс завершается без сброса буферов stdio или вызова обработчиков выхода.
Подробности этих различий в работе err_exit() станут понятнее при изучении главы 25, где рассматривается разница между _exit() и exit(), а также обработка буферов stdio и обработчики выхода в дочернем процессе, созданном с помощью fork(). А пока мы просто возьмем на заметку, что функция err_exit() будет особенно полезна при написании нами библиотечной функции, создающей дочерний процесс, который следует завершить по причине возникновения ошибки. Это завершение должно произойти без сброса дочерней копии родительских буферов stdio (то есть буферов вызывающего процесса) и без вызова обработчиков выхода, созданных родительским процессом.
Функция 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 *
void usageErr(const char *