int main(int argc, char **argv)  int main(int argc, char **argv)

{                                {

 /* здесь код */                  /* здесь код */

 return 0;                        /* ?? Что возвращает main()? */

}                                }

Стандарт С 1999 г. указывает, что при выпадении в конце, поведение функции main() должно быть таким, как если бы она возвращала 0. (Это верно также для С++; однако, стандарт С 1989 г. намеренно оставляет этот случай неопределенным.) Во всех случаях плохо полагаться на это поведение; однажды вы можете программировать для системы со скудной поддержкой С времени исполнения, или для внедренной системы, или где-то еще, где это будет по-другому. (В общем, выпадение в конце любой функции, не являющейся void — плохая мысль, которая может вести лишь к ошибочному коду.)

Возвращенное из main() значение автоматически передается обратно системе, от которой родительский процесс может его впоследствии получить. Мы опишем, как это делается, в разделе 9.1.6.1 «Использование функций POSIX: wait() и waitpid()».

ЗАМЕЧАНИЕ. На системах GNU/Linux управляемая компилятором команда c99 запускает компилятор с соответствующими опциями, так что возвращаемое значение при выпадении из конца функции равно 0. Простой gcc этого не делает.

<p>9.1.5.3. Функции завершения</p>

Другим способом естественного завершения программы является вызов функций завершения. Стандарт С определяет следующие функции:

#include /* ISO С */

void exit(int status);

void _Exit(int status);

int atexit(void (*function)(void));

Эти функции работают следующим образом:

void exit(int status)

Эта функция завершает программу, status передается системе для использования родителем. Перед завершением программы exit() вызывает все функции, зарегистрированные с помощью atexit(), сбрасывает на диск и закрывает все открытые потоки <stdio.h> FILE* и удаляет все временные файлы, созданные tmpfile() (см. раздел 12.3.2 «Создание и открытие временных файлов»). Когда процесс завершается, ядро закрывает любые оставшиеся открытыми файлы (которые были открыты посредством open(), creat() или через наследование дескрипторов), освобождает его адресное пространство и освобождает любые другие ресурсы, которые он мог использовать. exit() никогда не возвращается.

void _Exit(int status)

Эта функция в сущности идентична функции POSIX _exit(); мы на короткое время отложим ее обсуждение,

int atexit(void (*function)(void))

function является указателем на функцию обратного вызова, которая должна вызываться при завершении программы, exit() запускает функцию обратного вызова перед закрытием файлов и завершением. Идея в том, что приложение может предоставить одну или более функций очистки, которые должны быть запущены перед окончательным завершением работы. Предоставление функции называется ее регистрацией. (Функции обратного вызова для nftw() обсуждались в разделе 8.4.3.2 «Функция обратного вызова nftw()»; здесь та же идея, хотя atexit() вызывает каждую зарегистрированную функцию лишь однажды.)

atexit() возвращает 0 при успехе или -1 при неудаче и соответствующим образом устанавливает errno.

Следующая программа не делает полезной работы, но демонстрирует, как работает atexit():

/* ch09-atexit.c --- демонстрация atexit().

   Проверка ошибок для краткости опущена. */

/*

 * Функции обратного вызова здесь просто отвечают на вызов.

 * В настоящем приложении они делали бы больше. */

void callback1(void) { printf("callback1 called\n"); }

void callback2(void) { printf("callback2 called\n"); }

void callback3(void) { printf("callback3 called\n"); }

/* main --- регистрация функций и завершение */

int main(int argc, char **argv) {

 printf("registering callback1\n"); atexit(callback1);

Перейти на страницу:

Похожие книги