先从一个面试题说起:
C++中main函数执行完后还会执行完其他语句吗?
在学习C语言的时候,记得有一句话是这么说的,“C程序的执行是从main函数开始的,也是在main函数中结束整个程序的运行”。首先要说明一下,这句话是不正确的。严格意义上来说,程序开始运行的标识是程序的某一个制定的函数开始被调用。至于程序在哪个函数结束,C语言从来没有任何规定。
main结束不代表整个进程结束
(1)全局对象的构造函数会在main 函数之前执行,
全局对象的析构函数会在main函数之后执行;
用atexit注册的函数也会在main之后执行。
(2)一些全局变量、对象和静态变量、对象的空间分配和赋初值就是在执行main函数之前,而main函数执行完后,还要去执行一些诸如释放空间、释放资源使用权等操作
(3)进程启动后,要执行一些初始化代码(如设置环境变量等),然后跳转到main执行。全局对象的构造也在main之前。
这里我们看看那程序进程的终止方式:
共有8种方式可以使进程终止,其中前5种为正常终止。
1.从main返回
2.调用exit
3.调用_exit或者_Exit
4.最后一个线程从其启动例程返回
5.最后一个线程调用pthreead_exit
异常终止有3中,他们是:
6.调用abort
7.接到一个信号并终止
8.最后一个线程对取消请求做出响应
好了,再回到开始时候的面试问题,可以很明白main函数并不是程序执行完结束的地方,
事实上main函数结束时也会隐式的调用exit()函数,而exit()在结束调用它的进程之前,要进行如下步骤:
(1) cleanup();
(2) 调用在atexit()注册的函数
(3) 最后调用_exit()函数
所以,main函数在执行完以后还会隐含的执行exit()函数,这里面就包含用atexit()函数注册的程序正常终止时要被调用的函数。
下面主要讲一下exit()函数和atexit()函数:
1. exit()函数
exit()函数用于在程序运行的过程中随时结束程序,exit的参数state是返回给操作系统,返回0表示程序正常结束,非0表示程序非正常结束。main函数结束时也会隐式地调用exit函数。exit函数运行时首先会执行由atexit()函数登记的函数,然后会做一些自身的清理工作,同时刷新所有输出流、关闭所有打开的流并且关闭通过标准I/O函数tmpfile()创建的临时文件。
2. atexit()函数
函数声明:int atexit(void (*func)(void));
很多时候我们需要在程序退出的时候做一些诸如释放资源的操作,但程序退出的方式有很多种,比如main()函数运行结束、在程序的某个地方用exit()结束程序、用户通过Ctrl+C或Ctrl+break操作来终止程序等等,因此需要有一种与程序退出方式无关的方法来进行程序退出时的必要处理。方法就是用atexit()函数来注册程序正常终止时要被调用的函数。
atexit()函数的参数是一个函数指针,函数指针指向一个没有参数也没有返回值的函数。atexit()的函数原型是:int atexit (void (*)(void));
在一个程序中最多可以用atexit()注册32个处理函数,这些处理函数的调用顺序与其注册的顺序相反,也即最先注册的最后调用,最后注册的最先调用。
请看下面一个例子:
#include <stdlib.h> //使用atexit()函数必须包含头文件stdlib.h
#include <stdio.h>
void fn1()
{
printf("调用函数fn1()...\n");
}
void fn2()
{
printf("调用函数fn2()...\n");
}
int main()
{
atexit(fn1);
atexit(fn2);
printf("主程序正在退出...\n");
return 0;
}
运行结果:
主程序正在退出...
调用函数fn2()...
调用函数fn1()...
Press any key to continue