C语言中的程序终止函数

在C语言的标准库<stdlib.h>中提供了一些与正常或者不正常的程序终止有关的函数,下面分别对其进行简单介绍。

参考文献:

[1] C和指针,P298,342

[2] C程序设计语言现代方法(第2版),P489

[3] atexit函数和exit函数的理解

1 abort()

  abort()函数用于不正常地终止一个正在执行的程序。函数原型如下:

void abort(void)

  这个函数将引发SIGABRT信号,你可以在程序中为这个信号设置一个信号处理函数,在程序终止(或干脆不终止)之前采取任何你想采取的动作,甚至可以不终止程序。

  abort()函数类似于exit()函数,但调用它会导致异常的程序终止。atexit()函数注册的退出函数不会被调用。根据具体的实现,它可能不会清理包含未输出数据的输出缓冲区,不会关闭打开的流,也不会删除临时文件。abort()函数返回一个由实现定义的状态码来指出“不成功的终止”。

补充:

  调用abort()函数时,实际上会产生SIGABRT信号。如果没有处理SIGABRT信号的函数,那么程序会如前所述那样异常终止。如果(通过调用signal()函数)为SIGABRT安装了信号处理函数,那么就会调用处理函数。如果处理函数返回,随后程序会异常终止。但是,如果处理函数不返回(比如它调用了longjmp()函数),那么程序就不会终止。

2 atexit()

  atexit()函数可以把一些函数注册为退出函数(exit function)。函数原型如下:

int atexit(void (*func) (void))

  把函数指针传递给atexit()函数时,它会把指针保存起来留给将来引用。当程序将要正常终止时(或者由于调用exit,或者由于main函数返回),退出函数将被调用。退出函数不能接受任何参数

3 exit()

  exit()函数用于正常终止程序。函数原型如下:

void exit(int)

  如果程序以main函数返回一个值结束,那么其效果相当于用这个值作为参数调用exit()函数。在程序中的任何位置执行exit(n)调用通常等价于在main函数中执行return n。

  int参数返回给操作系统,用于提示程序是否正常完成。预定义符号EXIT_SUCCESSEXIT_FAILURE分别提示程序的终止成功还是失败。exit()函数仅有的另一个可移植参数是0,它和宏EXIT_SUCCESS的意义相同。虽然程序也可以使用其他值,但它们的具体含义将取决于编译器。

  当程序发现错误情况使它无法继续执行下去时,这个函数尤其有用。你经常会在调用perrno之后再调用exit()终止程序。尽管终止程序并非处理所有错误的正确方法,但和一个注定失败的程序继续执行以后再失败相比,这种做法更好一些。

  注意,这个函数没有返回值。当exit()函数结束时,程序已经消失,所以它无处返回。

  当exit()函数被调用时,所有被atexit()函数注册为退出函数的函数将按照它们所注册的顺序被反序依次调用(参数由于被压入栈中,而先进后出)。然后,所有用于流的缓冲区被刷新,所有打开的文件被关闭。用tmpfile()函数创建的文件被删除。然后,退出状态返回给宿主环境,程序停止执行。

警告:

  由于程序停止执行,所以exit()函数绝对不会返回到它的调用处。但是,如果任何一个用atexit()注册为退出函数的函数如果再次调用了exit(),其效果是未定义的。这个错误可能导致一个无限循环,很可能只有当堆栈的内存耗尽才会终止。

4 _exit()

  _exit()函数类似于exit()函数,但是_exit()不会调用atexit()注册的退出函数,也不会调用之前传递给signal()函数的信号处理函数。此外,_exit()函数不需要清洗输出缓冲区,关闭打开的流,以及删除临时文件,是否执行这些操作是由实现定义的。函数原型如下:

void _exit(int)

  按照ISO C规定,一个进程可以登记多达32个函数,通常这32个函数被称为终止处理程序(退出函数),通过调用atexit()函数来登记这些函数,这些函数将由exit()函数自动调用。

  exit()和_exit()以及_Exit()函数的本质区别是是否立即进入内核,_exit()以及_Exit()函数都是在调用后立即进入内核,而不会执行一些清理处理,但是exit()则会执行一些清理处理,这也是为什么会存在atexit()函数的原因,因为exit()函数需要执行清理处理,需要执行一系列的操作,这些终止处理函数实际上就是完成各种所谓的清除操作的实际执行体。atexit函数的定义也给了程序员一种运用exit执行一些清除操作的方法,比如有一些程序需要额外的操作,具体的清除操作可以采用这种方法对特殊操作进行清除等。

  内核使程序执行的唯一方法是调用一个exec()函数,进程自愿终止的唯一方法是显式或者隐式调用(通过exit函数)_exit()或者_Exit()函数。因此exit函数中实质是对_exit()或者_Exit()函数的封装。exit会先执行自定义的终止处理函数,然后执行I/O库函数清理函数fclose(),这也是为什么可以在终止处理函数中可以继续运用printf之类函数的原因,因为I/O库函数的流对象还没有被清除,当然可以继续运用。执行完了所有的fclose()以后,可以执行真正意义上的终止函数_exit()或者_Exit()函数。

时间: 2024-10-09 04:11:47

C语言中的程序终止函数的相关文章

C语言中的程序结构

C语言中的程序结构有三种,分别是顺序结构.选择结构和循环结构. 一.按照语句的先后顺序执行的程序结构,称为顺序结构. 下面以一个求三角形面积的例子进行说明,其代码如下: 例1.1 1 #include<stdio.h> 2 int main() 3 { 4 int width,height,s; 5 printf("请输入三角形的底宽:\n"); 6 scanf("%d",&width); 7 printf("请输入三角形的高:\n&q

【示例】C语言中利用数组存放函数指针

C语言中利用数组存放函数指针,增加函数使用的灵活性.使用时只需提供数组索引,即可调用不同函数. 预备知识: 1.指向函数的指针 一个函数在编译时被分配一个入口地址,这个地址就被称为函数的指针. 例如: int max(int,int); // 声明函数,比较两数大小 int (*p)(); //声明指向函数的指针变量 p=max; //将函数max的入口地址赋给指针变量p int c=(*p)(a,b); //调用函数 2.函数指针作为函数参数 该例子中每次给process函数不同实参(函数名)

C语言中关于时间的函数

C语言中关于时间的函数 本文从介绍基础概念入手,探讨了在C/C++中对日期和时间操作所用到的数据结构和函数,南平私家侦探(http://user.qzone.qq.com/778607337)并对计时.时间的获取.时间的计算和显示格式等方面进行了阐述.本文还通过大量的实例向你展示了time.h头文件中声明的各种函数和数据结构的详细使用方法. 关键字:UTC(世界标准时间),Calendar Time(日历时间),epoch(时间点),clock tick(时钟计时单元) 注:linux系统时间如

C语言中可变参数的函数(三个点,“...”)

C语言中可变参数的函数(三个点,"...") 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end这两个宏,但对它们也只是泛泛的了解. 介绍这两个宏之前先看一下C中传递函数的参数时的用法和原理: 1.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表 void foo(...); void foo(parm_list,...); 这种方式和我们以前认识的不大

C语言中的可变参数函数 三个点“…”printf( const char* format, ...)

第一篇 C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为: int printf( const char* format, ...); 它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的(用三个点“…”做参数占位符),实际调用时可以有以下的形式: printf("%d",i); printf("%s",s); printf("the number is %d ,string is:%s",

C语言中变量名及函数名的命名规则与驼峰命名法

一.C语言变量名的命名规则:(可以字母,数字,下划线混合使用) 1. 只能以字母或下划线开始:2. 不能以数字开始:3. 一般小写:4. 关键字不允许用(eg:int float=2//error  float 为保留字不允许用): 二.函数名的命名规则 1.见名知意:2.自定义函数函数名首字母大写(库函数里的函数名都是以小写字母定义,为了区分库函数和自定义函数,避免冲突). 三.宏定义里面的变量 全大写 eg:#define SIZE 100(后面函数所有出现的SIZE全用100代替,它在所有

C++基础 (8) 第八天 数组指针 模板指针 C语言中的多态 模板函数

1昨日回顾 2 多态的练习-圆的图形 3多态的练习-程序员薪资 4员工管理案例-抽象类和技术员工的实现 employee.h: employee.cpp: technician.h: technician.cpp: source.cpp: 5员工管理案例-销售和经理实现 修改employee.h: displayStatus不用虚函数了 salesman.h: salesman.cpp: manager.h: manager.cpp: 6员工管理案例-销售经理的实现 7 中午回顾 注意: 多继承

简答的理解C语言中的各种类型函数

1.变参函数 变长参数的函数即参数个数可变.参数类型不定 的函数.最常见的例子是printf函数.scanf函数和高级语言的Format函数.在C/C++中,为了通知编译器函数的参数个数和类型可变(即是不定的.未知的),就必须以三个点结束该函数的声明. 1 // printf函数的声明 2 int printf(const char * _Format, ...); //const char * _Format是格式控制,控制有多少个%d...,确定输出的个数与类型 3 4 //scanf函数声

万恶之源:C语言中的隐式函数声明

1 什么是C语言的隐式函数声明 在C语言中,函数在调用前不一定非要声明.如果没有声明,那么编译器会自己主动依照一种隐式声明的规则,为调用函数的C代码产生汇编代码.以下是一个样例: int main(int argc, char** argv) { double x = any_name_function(); return 0; } 单纯的编译上述源代码.并没有不论什么报错,仅仅是在链接阶段由于找不到名为any_name_function的函数体而报错. [[email protected] t