理解并区分C++中的exit()和::_Exit(), atexit()的作用
exit, _exit, _Exit 都是进程终止函数。
atexit 是在执行 exit 函数时设置要作的工作,实际就是调用要在进程退出想让程序执行的函数。
其参数是要调用的函数地址。参数函数是一个无参数无返回值的函数。atexit可以登记32个函数,这些函数由 exit 函数自动调用,登记的顺序和调用的顺序相反,即最后登记的先执行。同一函数登记多次也会调用多次。
exit :是一个C库标准函数。此函数执行会首先调用由 atexit注册的函数,然后执行关闭所有标准IO流,刷新流缓冲区等操作。对于常用的有返回值的 return 调用,相当于调用了 exit 。如 return(0)== exit(0);
_exit : 是一个系统调用。此函数不会调用 atexit 注册的函数,也不会运行信号处理程序。对标准IO流的缓冲区是否进行刷新取决于该函数在系统中的实现。一般UNIX下不会刷新。 exit函数会调用此函数。(在windows下的_exit函数会对标准IO流的缓冲进行刷新)
_Exit : 是一个C库标准函数。其动作类似 _exit 。
exit和_exit函数
exit和_exit函数用于正常终止一个程序: _exit立即进入内核, exit则先执行一些清除处理(包括调用执行各终止处理程序,关闭所有标准I / O流等),然后进入内核。
#include <stdlib.h>
void exit(int status);
#include <unistd.h>
void _exit (int status) ;
使用不同头文件的原因是:exit是由ANSI C说明的,而_exit则是由POSIX.1说明的。
由于历史原因, exit函数总是执行一个标准I/O库的清除关闭操作:对于所有打开流调用fclose函数。
注意,内核使程序执行的唯一方法是调用一个e x e c函数。进程自愿终止的唯一方法是显式或隐式地(调用e x i t )调用_ e x i t。进程也可非自愿地由一个信号使其终止。exit本身不是系统调用,而是一个C标准库的函数而已,在stdlib里面,系统调用是_exit内部实现去完成的。
如下代码说明了exit终止了一个程序
输出结果为:
如下代码说明了exit终止程序之前调用atexit以及调用的函数的顺序。
使用exit(0)和return 0的输出结果相同,如下所示:
可以看到先注册的exit_fn1后执行。并且注册的函数无参数无返回值。另外,如果使用_exit(0),则不会有输出结果,因为_exit(0)不执行atexit注册的函数。
如下是使用_exit(0)和exit(0)对标准IO缓冲区是否刷新的比较操作:
在linux和windows下执行exit均会输
output begin
contentbuffer
而在linux执行_exit则只会输出output begin,但是在windows下_exit仍同exit的输出
对应每个打开的文件,在内存中都有一片缓冲区。每次读文件时,会读出若干条记录,这样下次读文件就可以直接从内存的缓冲区中读取,每次写文件的时候也仅仅是写入内存中的缓冲区,等满足了一定条件(达到一定数量,遇到特定字符如换行符\n和文件结束符EOF),再将缓冲区中的内容一次性写入文件。
printf会根据参数format字符串来转换并格式化数据,然后将结果写到标准输出设备,直到出现字符串结束符\0为止。
可见,exit将未出现换行符的语句保存到标准输出文件。而由于第二条printf没有满足特定条件,只是保存在缓冲区,使用_exit()函数直接将进程关闭,缓冲区就会丢失。
return与exit的区别
在进程操作中exit是结束当前进程或程序并把控制权返回给调用该程序或者进程的进程即父进程并告诉父进程该当前进程的运行状态,而return是从当前函数返回,如果是在main函数中,main函数结束时隐式地调用exit函数,自然也就结束了当前进程。
return是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束。exit函数是退出应用程序,并将应用程序的一个状态返回给OS,这个状态标识了应用程序的一些运行信息。
在main函数里面return(0)和exit(0)是一样的,子函数用return返回;而子进程用exit退出,调用exit时要调用一段终止处理程序,然后关闭所有I/O流。
推荐阅读
-
Java 类加载器的作用 - 简介:类加载器是 Java™ 中一个非常重要的概念。类加载器负责将 Java 类的字节码加载到 Java 虚拟机中。本文首先详细介绍了 Java 类加载器的基本概念,包括代理模型、加载类的具体过程和线程上下文类加载器等。然后介绍了如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi™ 中的应用。 类加载器是 Java 语言的一项创新,也是 Java 语言广受欢迎的重要原因之一。它允许将 Java 类动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 开始出现,最初是为了满足 Java Applets 的需求而开发的,Java Applets 需要从远程位置下载 Java 类文件并在浏览器中执行。现在,类加载器已广泛应用于网络容器和 OSGi。一般来说,Java 应用程序的开发人员不需要直接与类加载器交互;Java 虚拟机的默认行为足以应对大多数情况。但是,如果遇到需要与类加载器交互的情况,而您又不太了解类加载器的机制,就很容易花费大量时间调试异常,如 ClassNotFoundException 和 NoClassDefFoundError。本文将详细介绍 Java 的类加载器,帮助读者深入理解 Java 语言中的这一重要概念。下面先介绍一些基本概念。 类加载器的基本概念 顾名思义,类加载器用于将 Java 类加载到 Java 虚拟机中。一般来说,Java 虚拟机以如下方式使用 Java 类:Java 源程序(.java 文件)经 Java 编译器编译后转换为 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码并将其转换为 java.lang 实例。每个实例都用来表示一个 Java 类。通过该实例的 newInstance 方法创建该类的对象。实际情况可能更加复杂,例如,Java 字节代码可能是由工具动态生成或通过网络下载的。 基本上,所有类加载器都是 java.lang.ClassLoader 类的实例。下面将详细介绍这个 Java 类。 java.lang.ClassLoader 类简介 java.lang.ClassLoader 类的基本职责是根据给定类的名称为其查找或生成相应的字节码,然后根据这些字节码定义一个 Java 类,即 java.lang.Class 类的实例。除此之外,ClassLoader 还负责加载 Java 应用程序所需的资源,如图像文件和配置文件。不过,本文只讨论它加载类的功能。为了履行加载类的职责,ClassLoader 提供了许多方法,其中比较重要的方法如表 1 所示。下文将详细介绍这些方法。 表 1.与加载类相关的 ClassLoader 方法
-
理解并应用C++中的atexit函数:实例详解
-
理解并探索exit和atexit函数的作用
-
理解C/C++中的abort、atexit、exit和_Exit函数的作用与区别
-
理解 atexit 函数和 exit 函数的区别
-
理解exit、_exit、atexit和on_exit的差异与用法
-
进程调度:深入理解exit和wait4的作用
-
理解并比较C语言的atexit函数与_exit函数
-
理解编程中的退出函数:exit(1),abort和assert(0)
-
理解C++编程中的use-cxa-atexit和no-use-cxa-atexit编译选项