C标准定义了下面的退出函数:shell
#include <stdlib.h>缓存
void exit(int status);数据结构
void _Exit(int status);ide
int atexit(void (*function)(void));函数
函数功能介绍以下:测试
void exit(int status)spa
该函数终止调用的程序。status传递给系统用于父进程恢复。程序退出以前,exit()调用全部以atexit()注册的函数,清空全部打开的<stdio.h> FILE*流的缓冲区并关闭流,而后删除全部由tmpfile()建立的临时文件。进程退出时,内核关闭全部剩下的已打开文件(即那些由open()、creat()或文件描述符继承打开的文件),释放其地址空间,而后释放全部其余使用的资源。exit()从不返回。指针
void _Exit(int status)继承
该函数基本上与POSIX的_exit()函数相同。进程
int atexit(void (*function)(void))
function是一个函数指针,指向程序退出时候调用的一个回调函数。exit()在其关闭文件和终止以前调用该回调函数。这个想法在于程序可以在最终关闭以前提供一个或者多个运行的清理函数。提供一个函数被成为注册该函数。
atexit()成功时返回0,出错时返回-1并设置相应的errno。
下面的程序没有有用的功能,但它演示了如何使用atexit():
void callback1(void){printf("callback called\n");}
void callback2(void)(printf("callback called\n");}
void callback3(void)(printf("callback called\n");}
int main(int argc,char* argv[])
{
printf("registering callback1\n");atexit(callback1);
printf("registering callback2\n");atexit(callback2);
printf("registering callback3\n");atexit(callback3);
printf("exiting now\n");
exit(0);
}
下面是程序的运行结果:
$atexit
registering callback1
registering callback2
registering callback3
exiting now
callback3 called
callback2 called
callback1 called
正如上例所示,使用atexit()注册的函数运行时的顺序和注册的顺序相反:最近注册的最早运行(这也称为后进先出(last-in-first-out),缩写为LIFO)。
POSIX定义了_exit()函数。与exit()不一样,exit()调用回调函数并进行<stdio.h>清理,_exit()是“当即死亡”的函数:
#include <unistd.h>
void _exit(int status);
_exit终止调用进程,但不关闭文件,不清除输出缓存,也不调用出口函数。exit函数将终止调用进程。在退出程序以前,全部文件关闭,缓冲输出内容将刷新定义,并调用全部已刷新的“出口函数”(由atexit定义)。
实际上,ISO C的_Exit()函数与_exit()相同。C函数指出_Exit()是否调用以atexit()注册的函数并关闭打开的文件取决与实现。对于GLIBC系统,可能不会,即_Exit()与_exit()表现类似。
使用_exit()的时机是在fork()产生的子进程中调用exec()失败的时候。这种状况下,不须要使用一般的exit(),由于它会清空全部由FILE*流保存的缓冲区数据。随后父进程清空其缓冲区拷贝时,致使缓冲的数据被写了两次;显然这不是很恰当。
例如,加入你运行了一个shell命令,而且本身调用fork()和exec()。代码可能以下所示:
char *shellcommand="...";
pid_t child;
if((child=fork())==0){
execl("/bin/sh","sh","-c",shellcommand,NULL);
_exit(errno==ENOENT?127:126);
}
errno测试和退出值采起了POSIX shell所使用的惯例。若是要求的程序没有退出(ENOENT——目录中没有它的项),则退出值为127。不然,文件一样退出,但因为其余缘由不可以被exec()执行,则退出状态为126。在你本身的程序中采起这个惯例将会是个好主意。
简言之,为了更好地使用exit()和atexit(),你应该遵循一下规则:
1、定义一个较小的退出状态值的集合,你的程序使用该集合中的值与其调用者进行通讯。在你的代码中使用#define常量或enum定义这些值。
2、决定是否有必要与atexit()一块儿使用回调函数。若是有必要,则在main()中适当地方注册这些函数;例如,在解析选项以后以及初始化任何回调函数可能清除的数据结构以后,记住函数以LIFO(last-in-first-out)顺序进行调用。
3、若是出错,在任一地方均可以使用exit()从程序退出,退出是可以发生的正确行为。同时使用你定义的错误代码。
4、main()函数是个例外,你能够在其中使用return。咱们本身的风格是,一般出问题时使用exit(),而若是一切正常,在main()结尾处使用“return 0”。
5、若是调用exec()失败,则在子进程中使用_exit()或_Exit()。