说明:只供学习交流,装载请注明出处
正常中止一个程序,可以使用从main函数中返回、调用exit函数或_exit函数的方法。从main函数中返回这一方法,常用于获得程序返回值这一场合。这时,除了需要定义main函数的类型外,在程序中还需要使用return语句。使用这一方法退出程序只能用于主函数中,用在子程序中只能返回上一级调用程序。
exit函数和_exit函数可以用在子程序中。程序在执行到这两个函数处,会自动结束并跳回到操作系统中。当然,也可以将这两个函数用在main函数中。与使用return相比,exit和_exit是不考虑返回类型的,也就是说,main的类型可以是void或任意类型。
一个简单的例子:
#include <stdio.h>
#include <stdlib.h>
void Exit_Test(void)
{
printf("Hello linux!\n");
exit(0);
}
int main(void)
{
Exit_Test();
printf("Hello word!\n");
return (0);
}
输出结果:
[root@localhost test]# ./exit
Hello linux!
说明:程序并没有输出“helloword!”,因为程序运行到exit出了直接退出并跳到操作系统中。
exit函数:
exit函数的定义信息如下表:
头文件 | #include <stdlib.h> | ||
函数原型 | void exit(int status) | ||
返回值 | 成功 | 失败 | 是否设置errno |
—— | —— | —— |
说明:调用exit函数结束进程,并将(status & 0377)获得的结果返回给父进程。使用exit函数结束进程时,会首先执行使用atexit函数注册的函数,然后调用on_exit函数中清理动作。函数执行顺序与注册的顺序相反。
参数status为退出进程时的状态,父进程将获得该状态值。C语言标准指定了EXIT_SUCCESS和EXIT_FAILURE作为程序正常结束和异常中止的两个宏。
为了说明使用exit函数退出程序是会执行的相关的动作,这里给出一个简单的实例。程序用atexit注册了一个进程退出时的处理函数,该处理函数只是显示一段文字信息。main函数退出时将调用exit函数,这样进程就会在退出时自动调用atexit注册的处理函数。
atexit函数定义如下:
int atexit(void (*function) (void));
atexit在成功注册回调函数后会返回0值,否则返回返回非0值。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void do_at_exit(void)
{
printf("You can see the output when the program terminates\n");
}
int main(void)
{
int flag;
flag = atexit(do_at_exit);
if ( flag != 0 )
{
printf("Cannot set exit function!\n");
return (EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
运行结果:
[root@localhost test]# ./atexit
You can see the output when the program terminates
[root@localhost test]#
说明:在main中调用return函数同样会在程序退出时执行使用atexit注册的处理动作。因此,使用return代替exit函数同样会获得相同的结果。
_exit函数:
与exit函数类似,_exit函数同样可以用于退出进程,这两个函数存在一定的区别。在介绍vfork函数的使用时,提到了子进程的退出只能使用_exit函数,具体原因并没有阐述。这里首先介绍其定义,然后通过实例来说明它们之间的区别。
_exit函数的定义如下表:
头文件 | #include <unistd.h> | ||
函数原型 | void _exit(int status) | ||
返回值 | 成功 | 失败 | 是否设置errno |
—— | —— | —— |
说明:_exit函数将立即结束调用它的进程,与进程相关的任何打开的文件描述符都将关闭,进程的子进程都将变为init进程(进程号为1)的子进程。
参数status为退出进程时的状态,父进程将获得该状态值。C语言标准指定了EXIT_SUCCESS和EXIT_FAILURE作为程序正常结束和异常中止的两个宏。
我们同样使用上面的那个实例,只是把exit该为_exit退出,其他的都是一样,之所以使用同一个例子是为了说明_exit退出程序时,不会执行atexit注册的处理函数。
实例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void do_at_exit(void)
{
printf("You can see the output when the program terminates\n");
}
int main(void)
{
int flag;
flag = atexit(do_at_exit);
if ( flag != 0 )
{
printf("Cannot set exit function!\n");
return (EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
运行结果:
[root@localhost test]# ./atexit
[root@localhost test]#
exit函数与_exit函数的区别:
(1):exit函数只是在ANSI C中说明的,而_exit函数是在POSIX标准中说明的。
(2):exit函数将终止调用进程,在退出程序之前所有文件关闭,标准输入输出的缓冲区被清空,并执行在atexit注册的回调函数;_exit终止调用进程,但不关闭文件,不清除标准输入输出缓存区,也不调用在atexit注册的回调函数。
说明:在系统调用fork创建的子进程中,一般情况下尽量不要使用exit函数退出子进程。因为exit会导致标准输入输出的缓冲区被清空。对应C++程序,问题可能会更严重。exit函数有可能导致静态目标文件中的析构函数被错误执行。使用exit函数时,必须保证exit在进入main函数后只会被调用一次。而使用vfork时,由于父子进程共享虚拟内存空间,子进程使用exit将会影响父进程的状态。