exit、_exit、函数与return的不同

来源:互联网 发布:java ee书籍推荐 编辑:程序博客网 时间:2024/05/23 01:26

 

说明:只供学习交流,装载请注明出处

 

正常中止一个程序,可以使用从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_SUCCESSEXIT_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_SUCCESSEXIT_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将会影响父进程的状态。

 

 

 

 

 

 

 

 

 

 

原创粉丝点击