Шрифт:
Помимо системных вызовов программисту предлагается большой набор функций общего назначения. Эти функции не являются точками входа в ядро операционной системы, хотя в процессе выполнения многие из них выполняют системные вызовы. Например, функция printf(3S) использует системный вызов write(2) для записи данных в файл, в то время как функции strcpy(3C) (копирование строки) или atoi(3C) (преобразование символа в его числовое значение) вообще не прибегают к услугам операционной системы. Функции, о которых идет речь, хранятся в стандартных библиотеках С и наряду с системными вызовами составляют основу среды программирования в UNIX. Подробное описание этих функций приведено в разделе 3 электронного справочника.
Таким образом, часть библиотечных функций является "надстройкой" над системными вызовами, обеспечивающей более удобный способ получения системных услуг. В качестве примера рассмотрим процесс получения текущей даты и времени. Соответствующий системный вызов time(2) возвращает время в секундах, прошедшее с момента Epoch: 1 января 1970 года. Дополнительная интерпретация этого значения, такая как преобразование в вид, удобный для восприятия (дата и время) с учетом временной зоны, осуществляется библиотечными функциями (ctime(3C), localtime(3C) и т.д.). К этим функциям можно отнести функции библиотеки ввода/вывода, функции распределения памяти, часть функций управления процессами и т.д.
На рис. 2.1 показана схема взаимодействия приложения с ядром операционной системы при использовании системных вызовов и библиотечных функций.
Рис. 2.1. Системные вызовы и библиотечные функции
Обработка ошибок
В предыдущем разделе мы обсудили разницу между системными вызовами и библиотечными функциями. Они также различаются по способу передачи процессу информации об ошибке, произошедшей во время выполнения системного вызова или функции библиотеки.
Обычно в случае возникновения ошибки системные вызовы возвращают и устанавливают значение переменной errno, указывающее причину возникновения ошибки. Так, например, существует более десятка причин завершения вызова open(2) с ошибкой, и все они могут быть определены с помощью переменной errno. Файл заголовков <errno.h> содержит коды ошибок, значения которых может принимать переменная errno, с краткими комментариями.
Библиотечные функции, как правило, не устанавливают значение переменной errno, а код возврата различен для разных функций. Для уточнения возвращаемого значения библиотечной функции необходимо обратиться к электронному справочнику man(1).
Поскольку базовым способом получения услуг ядра являются системные вызовы, рассмотрим более подробно обработку ошибок в этом случае.
Переменная errno определена следующим образом:
Следует обратить внимание, что значение errno не обнуляется следующим нормально завершившимся системным вызовом. Таким образом, значение errno имеет смысл только после системного вызова, который завершился с ошибкой.
Стандарт ANSI С определяет две функции, помогающие сообщить причину ошибочной ситуации: strerror(3C) и perror(3C).
Функция strerror(3C) имеет вид:
Функция принимает в качестве аргумента errnum номер ошибки и возвращает указатель на строку, содержащую сообщение о причине ошибочной ситуации.
Функция perror(3C) объявлена следующим образом:
Функция выводит в стандартный поток сообщений об ошибках информацию об ошибочной ситуации, основываясь на значении переменной errno. Строка s, передаваемая функции, предваряет это сообщение и может служить дополнительной информацией, например содержа название функции или программы, в которой произошла ошибка.
Следующий пример иллюстрирует использование этих двух функций:
Запустив программу, мы получим следующий результат на экране:
Эти функции используются, в частности, командным интерпретатором и большинством стандартных утилит UNIX. Например: