理解C语言中的花式退出
代码test_Exit.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 //简单输出fun1被调用的提示信息 6 void fun1(void){ 7 printf("[%s] is called...\n", __FUNCTION__); 8 } 9 10 //简单输出fun2被调用的提示信息 11 void fun2(void){ 12 printf("[%s] is called...\n", __FUNCTION__); 13 } 14 15 int main(int argc, char **argv) 16 { 17 //表示在要在函数退出前进行函数的调用 18 atexit(fun1); 19 //调用顺序为LIFO方式,也就是说先执行第20行,再执行第18行 20 atexit(fun2); 21 22 //printf()函数中没有\n,也就是只输出,不刷新 23 printf("abcdef"); 24 25 //_exit()是一种退出,这种退出不处理退出函数,也不刷新IO 26 _exit(0); 27 }
程序很简单,不多说明
结果是:
对,你没有看错,就是什么也没有,什么也没有了。虽然调用了printf()函数输出了字符串,但是函数退出前没有刷新IO,所有字符串并没有被输出。
接下来testN_exit.c,将23行改为:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 //简单输出fun1被调用的提示信息 6 void fun1(void){ 7 printf("[%s] is called...\n", __FUNCTION__); 8 } 9 10 //简单输出fun2被调用的提示信息 11 void fun2(void){ 12 printf("[%s] is called...\n", __FUNCTION__); 13 } 14 15 int main(int argc, char **argv) 16 { 17 //表示在要在函数退出前进行函数的调用 18 atexit(fun1); 19 //调用顺序为LIFO方式,也就是说先执行第20行,再执行第18行 20 atexit(fun2); 21 22 //printf()函数中添加\n,也就是既输出,又刷新 23 printf("abcdef\n"); 24 25 //_exit()是一种退出,这种退出不处理退出函数,也不刷新IO 26 _exit(0); 27 }
结果是:
abcdef
表明_exit(0)只负责退出,而刷新IO只能靠\n解决了
接下来:testExit.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 //简单输出fun1被调用的提示信息 6 void fun1(void){ 7 printf("[%s] is called...\n", __FUNCTION__); 8 } 9 10 //简单输出fun2被调用的提示信息 11 void fun2(void){ 12 printf("[%s] is called...\n", __FUNCTION__); 13 } 14 15 int main(int argc, char **argv) 16 { 17 //表示在要在函数退出前进行函数的调用 18 atexit(fun1); 19 //调用顺序为LIFO方式,也就是说先执行第20行,再执行第18行 20 atexit(fun2); 21 22 //printf()函数中没有\n,也就是只输出,不刷新 23 printf("abcdef"); 24 25 //_exit()是一种退出,这种退出不处理退出函数,也不刷新IO 26 exit(0); 27 }
相较test_Exit.c只是把_exit()换成了exit(),代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 //简单输出fun1被调用的提示信息 6 void fun1(void){ 7 printf("[%s] is called...\n", __FUNCTION__); 8 } 9 10 //简单输出fun2被调用的提示信息 11 void fun2(void){ 12 printf("[%s] is called...\n", __FUNCTION__); 13 } 14 15 int main(int argc, char **argv) 16 { 17 //表示在要在函数退出前进行函数的调用 18 atexit(fun1); 19 //调用顺序为LIFO方式,也就是说先执行第20行,再执行第18行 20 atexit(fun2); 21 22 //printf()函数中没有\n,也就是只输出,不刷新 23 printf("abcdef"); 24 25 //exit()这种退出,不但处理退出函数,而且刷新IO 26 exit(0); 27 }
结果:
abcdef[fun2] is called... [fun1] is called...
就会发现,exit()函数不但完成了刷新IO的任务,同时也完成函数退出前的所有任务,调用atexit()函数是按照栈的方式调用的,但是还是有点缺陷的。
下面testNExit.c为:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 //简单输出fun1被调用的提示信息 6 void fun1(void){ 7 printf("[%s] is called...\n", __FUNCTION__); 8 } 9 10 //简单输出fun2被调用的提示信息 11 void fun2(void){ 12 printf("[%s] is called...\n", __FUNCTION__); 13 } 14 15 int main(int argc, char **argv) 16 { 17 //表示在要在函数退出前进行函数的调用 18 atexit(fun1); 19 //调用顺序为LIFO方式,也就是说先执行第20行,再执行第18行 20 atexit(fun2); 21 22 //printf()函数中有\n,也就是不但输出,而且刷新 23 printf("abcdef\n"); 24 25 //exit()是这种退出,不但处理退出函数,同时刷新IO 26 exit(0); 27 }
结果为:
abcdef [fun2] is called... [fun1] is called...
很明显可以看出,exit()完成了IO的刷新,\n完成了换行,终于实现了我们需要的结果,其实这里的exit(0)完全等价于我们的return 0语句,它也只不过是个宏定义而已。
人就像是被蒙着眼推磨的驴子,生活就像一条鞭子;当鞭子抽到你背上时,你就只能一直往前走,虽然连你也不知道要走到什么时候为止,便一直这么坚持着。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具