Linux программирование в примерах
Мы представим программу сверху вниз, начав с командной строки. В последующих разделах мы представим обработку ошибок, а затем перейдем к сущностным задачам, показав, каким образом осуществляется реальный файловый ввод/вывод.
4.2. Представление базовой структуры программы
Наша версия cat следует структуре, которая обычно является полезной. Первая часть начинается с комментариев, заголовочных файлов, объявлений и функции main():
1 /*2 * ch04-cat.c --- Демонстрация open(), read(), write(), close(),3 * errno и strerror().4 */56 #include <stdio.h> /* для fprintf(), stderr, BUFSIZ */7 #include <errno.h> /* объявление errno */8 #include <fcntl.h> /* для flags для open() */9 #include <string.h> /* объявление strerror() */10 #include <unistd.h> /* для ssize_t */11 #include <sys/types.h>12 #include <sys/stat.h> /* для mode_t */1314 char *myname;15 int process(char *file);1617 /* main --- перечислить аргументы файла */1819 int20 main(int argc, char **argv)21 {22 int i;23 int errs = 0;2425 myname = argv[0];2627 if (argc == 1)28 errs = process("-");29 else30 for (i = 1; i < argc; i++)31 errs += process(argv[i]);3233 return (errs != 0);34 }…продолжение далее в главе.
Переменная
(строка 14) используется далее для сообщений об ошибках;mynameпервым делом устанавливает в ней имя программы (main()). Затемargv[0]в цикле перечисляет аргументы. Для каждого аргумента она вызывает функциюmain().process()Когда в качестве имени файла дано
(простая черточка, или знак минус),-Unix вместо попытки открыть файл с именем читает стандартный ввод. Вдобавок,catчитает стандартный ввод, когда нет аргументов.catреализует оба этих поведения. Условие 'ch04-cat' (строка 27) истинно, когда нет аргументов имени файла; в этом случаеargc == 1передает «main()» функции-. В противном случае,process()перечисляет аргументы, рассматривая их как файлы, которые необходимо обработать. Если один из них окажется «main()», программа обрабатывает стандартный ввод.-Если
возвращает ненулевое значение, это означает, что случилась какая- то ошибка. Ошибки подсчитываются в переменнойprocess()(строки 28 и 31). Когдаerrsзавершается, она возвращает 0, если не было ошибок, и 1, если были (строка 33). Это довольно стандартное соглашение, значение которого более подробно обсуждается в разделе 9.1.5.1 «Определение статуса завершения процесса».main()Структура, представленная в
, довольно общая:main()может делать с файлом все, что мы захотим. Например (игнорируя особый случай «process()»), process() также легко могла бы удалять файлы вместо их объединения!-Прежде чем рассмотреть функцию
, нам нужно описать, как представлены ошибки системных вызовов и как осуществляется ввод/вывод. Сама функцияprocess()представлена в разделе 4.4.3 «Чтение и запись».process()4.3. Определение ошибок
«Если неприятность может произойти, она случается»
«Будь готов»
Ошибки могут возникнуть в любое время. Диски могут заполниться, пользователи могут ввести неверные данные, сетевой сервер, с которого осуществляется чтение, может отказать, сеть может выйти из строя и т.д. Важно всегда проверять успешность завершения каждой операции.
Основные системные вызовы Linux почти всегда возвращают при ошибке -1 и 0 или положительное значение при успехе. Это дает возможность узнать, была операция успешной или нет:
int result;result = some_system_call(param1, param2);if (result < 0) {/* ошибка, что-нибудь сделать */} else/* все нормально, продолжить */Знания того, что произошла ошибка, недостаточно. Нужно знать, какая произошла ошибка. Для этого у каждого процесса есть предопределенная переменная с именем
. Всякий раз, когда системный вызов завершается ошибкой,errnoустанавливается в один из набора предопределенных значений ошибокerrnoи предопределенные значения ошибок определены в файле заголовкаerrno.<errno.h>#include <errno.h> /* ISO С */extern int errno;Хотя сама
может быть макросом, который действует подобно переменнойerrno— она не обязательно является действительной целой переменной. В частности, в многопоточном окружении у каждого потока будет своя индивидуальная версияint. Несмотря на это, практически для всех системных вызовов и функций в данной книге вы можете рассматриватьerrnoкак простуюerrno.int