c语言想要多次用main函数,C语言main函数之外

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

C语言的入口函数是main函数,程序通过找到main函数,作为整个程序的入口,顺序执行,执行完main函数之后结束程序。

但是我们想,全局变量、对象的构造在什么时候执行呢?肯定是在main函数之前就被构造了,但是这个过程又不会发生在编译期间,由此分析,在main函数之前有一段代码先执行了。

首先是由操作系统为这个程序创建进程,然后把控制权移交给程序入口(这个入口通常是程序运行库中的某个入口函数)。

入口函数对运行库和程序运行环境进行初始化,包括堆、I/O、线程、全局变量的构造等等。

入口函数执行完毕,调用main函数,正式开始执行函数主体部分。

main函数执行完毕之后,返回到入口函数,入口函数进行清理工作,包括全局变量析构、堆销毁、关闭I/O等,然后进行系统调用结束进程。

main函数执行之前

对静态变量、全局变量和全局对象来说的分配是早在main()函数之前就完成的

举个小例子:1

2

3

4

5

6

7

8

9

10

11int ();

int i = foo();

int (){

printf("Before mainn");

return 0;

}

int main(){

printf("Mainn");

return 0;

}

main函数执行之后

全局对象的析构函数会在main函数之后执行

用atexit注册的函数也会在main之后执行

通过对上面main函数执行之前的分析,我们可以理解全局对象的析构会发生在main函数之后。现在重点介绍atexit函数。

exit函数

有些程序会在一些语句中做判断,如果遇到异常情况会退出程序,通常会使用会exit语句。根据exit()函数中的参数可以分析出程序大致出错原因。函数原型为:

void exit(int state);

顺便介绍exit与return的区别

参考return is an instruction of the language that returns from a function call

exit is a system call(not a language statement) that terminates the current process.

return是在函数中用作返回使用的,而exit是终止当前进程的一个系统调用。

只有在main函数中他们的行为才比较相像。1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17#include

void f1(){

printf("f1n");

return ;

}

void fun2(){

printf("f2n");

exit(0); // 整个程序被终止

}

int main(){

f1();

printf("back from f1n");

f2();

printf("back from f2n"); // 不会执行到这一句,程序在fun2中就被终止

return 0;

}

main函数结束时也会隐式地调用exit()函数。

exit()函数运行时首先会执行由atexit()函数登记的函数,然后会做一些自身的清理工作,同时刷新所有输出流、关闭所有打开的流并且关闭通过标准I/O函数tmpfile()创建的临时文件。

atexit函数

atexit()函数用于注册终止函数(即main执行结束后调用的函数),其原型为:

int atexit(void (*function)(void));

很多时候我们需要在程序退出的时候做一些诸如释放资源的操作,这个时候就需要注册main函数执行完之后的函数了。

atexit()函数的参数是一个函数指针,函数指针指向一个没有参数也没有返回值的函数。

在一个程序中最多可以用atexit()注册32个处理函数,这些处理函数的调用顺序与其注册的顺序相反,也即最先注册的最后调用,最后注册的最先调用。同一个函数如若登记多次,则也会被调用多次。

当atexit注册的函数中有一个没有正常返回或被kill,则后续的注册函数都不会被执行。1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28#include

#include

#include

void fun1()

{

printf("fun1 is calledn");

}

void fun2()

{

printf("fun2 is calledn");

kill(getpid(),SIGINT);

}

int main(void)

{

printf("main functionn");

if(signal(SIGINT,SIG_DFL) == SIG_ERR){

perror("signal error");

exit(EXIT_FAILURE);

}

atexit(fun1);

atexit(fun2);

atexit(fun1);

return 0;

}

最先被注册的fun1不会执行

exit、_exit、atexit

进程终止有5种方式:

正常退出:从main函数返回、调用exit函数、调用_exit函数

异常退出:调用abort函数、由信号终止

exit和_exit区别

其中exit函数和_exit函数有些许区别,总结来说就是 exit = 清除I/O缓冲 + _exit

b69ac3dd476aab8c5e428e9f441e6b74.png

两个函数在不同的文件中定义1

2

3

4

5#include

void _exit(int status);

#include

void exit(int status);

_exit()函数直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构。

exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是”清理I/O缓冲”。

exit过程和atexit函数

exit()在结束调用它的进程之前,要进行如下步骤:调用atexit()注册的函数(出口函数);按atexit注册时相反的顺序调用所有由它注册的函数,这使得我们可以指定在程序终止时执行自己的清理动作。例如,保存程序状态信息于某个文件,解开对共享数据库上的锁。

cleanup();关闭所有打开的流,这将导致写所有被缓冲的输出,删除用TMPFILE函数建立的所有临时文件。

最后调用_exit()函数终止进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值