return和exit
来源:互联网 发布:网络歌手灰色天空 编辑:程序博客网 时间:2024/05/18 02:01
return和exit
标签(空格分隔): APUE
在每个函数结束之后,习惯上都会return一下。而在main函数里面,既可以用return,也可以用exit来结束进程。现在来看看return到底做了什么。
先写一个简单的C程序:
#include<stdio.h>int add(int ,int);int main(){ int a = 1; int b = 2; int c = add(a, b); return 1; }int add(int a, int b){ int c =a + b; return c;}
然后反汇编,看看汇编的东西:
080483ed <main>: 80483ed: 55 push %ebp 80483ee: 89 e5 mov %esp,%ebp 80483f0: 83 e4 f0 and $0xfffffff0,%esp 80483f3: 83 ec 20 sub $0x20,%esp 80483f6: c7 44 24 14 01 00 00 movl $0x1,0x14(%esp) 80483fd: 00 80483fe: c7 44 24 18 02 00 00 movl $0x2,0x18(%esp) 8048405: 00 8048406: 8b 44 24 18 mov 0x18(%esp),%eax 804840a: 89 44 24 04 mov %eax,0x4(%esp) 804840e: 8b 44 24 14 mov 0x14(%esp),%eax 8048412: 89 04 24 mov %eax,(%esp) 8048415: e8 0b 00 00 00 call 8048425 <add> 804841a: 89 44 24 1c mov %eax,0x1c(%esp) 804841e: b8 00 00 00 00 mov $0x0,%eax 8048423: c9 leave 8048424: c3 ret 08048425 <add>: 8048425: 55 push %ebp 8048426: 89 e5 mov %esp,%ebp 8048428: 83 ec 10 sub $0x10,%esp 804842b: 8b 45 0c mov 0xc(%ebp),%eax 804842e: 8b 55 08 mov 0x8(%ebp),%edx 8048431: 01 d0 add %edx,%eax 8048433: 89 45 fc mov %eax,-0x4(%ebp) 8048436: 8b 45 fc mov -0x4(%ebp),%eax 8048439: c9 leave 804843a: c3 ret
其他的不用管,只要看两个程序的结尾,可以看到,两个程序最后面的内容。后面如果是有返回值的return,则相当于如下三条指令:
804841e: b8 00 00 00 00 mov $0x0,%eax 8048423: c9 leave 8048424: c3 ret
第一条指令是给eax寄存器附上返回值,后面的两条指令,相当于:
mov %ebp,%esppop %ebppop %rip
稍微有一点寄存器基础的,就知道,这三条指令是函数栈的回收。即return就是函数栈的回收指令。
下面再来看下exit。
和上面一样的程序,只是在main里面用exit(0)来退出程序。反汇编得到的汇编如下:
0804841d <main>: 804841d: 55 push %ebp 804841e: 89 e5 mov %esp,%ebp 8048420: 83 e4 f0 and $0xfffffff0,%esp 8048423: 83 ec 20 sub $0x20,%esp 8048426: c7 44 24 14 01 00 00 movl $0x1,0x14(%esp) 804842d: 00 804842e: c7 44 24 18 02 00 00 movl $0x2,0x18(%esp) 8048435: 00 8048436: 8b 44 24 18 mov 0x18(%esp),%eax 804843a: 89 44 24 04 mov %eax,0x4(%esp) 804843e: 8b 44 24 14 mov 0x14(%esp),%eax 8048442: 89 04 24 mov %eax,(%esp) 8048445: e8 10 00 00 00 call 804845a <add> 804844a: 89 44 24 1c mov %eax,0x1c(%esp) 804844e: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048455: e8 a6 fe ff ff call 8048300 <exit@plt>
可以看到和上面不一样的是:
804844e: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048455: e8 a6 fe ff ff call 8048300 <exit@plt>
他把esp所指向的地址里面的内容改为了0,然后调用exit。这里和上面的return不一样的是,他没有摧毁栈,然后返回上一级函数。
而exit()的作用是调用_exit()或者_Exit()系统调用,来直接结束进程。
再来说下atexit()函数。
int atexit(void (*func) (void));
通俗来说,atexit函数是一个终止处理程序,他登记那些想在退出main函数之后,再执行的函数,这些函数会在exit()函数中被调用。这里要注意两点:1.登记的函数只能是无输入无输出的函数。2.最后在exit函数中,调用终止处理程序的顺序和登记的时候是相反的。
关于第二点函数执行顺序的原因说一下自己的猜想:感觉应该是在atexit函数执行的时候,只是把函数指针压入exit的函数栈里面,所以根据栈的特性,最后的执行顺序和压入顺序是反的。
看一下例子:
#include<stdio.h>#include<stdlib.h>void print1(){ printf("exit1\n"); }void print2(){ printf("exit2\n");}int main(){ atexit(print1); atexit(print1); atexit(print2); return 0;}
结果是:
可以看到他的执行顺序是反过来的。而且注意,在C程序里面,最后的返回是用的return而不是exit。而终止处理程序实在exit函数里面掉用的。所以简单来说,在main函数里面return到了main函数的上层函数,在上层函数里面依旧调用了exit函数。
总结return和exit:
return只是一个销毁函数栈的指令,在销毁函数栈之后,会调到调用函数中去。而exit是三个作用:执行终止处理程序(注意执行顺序),清理标准I/O,调用_exit或者_Exit系统调用,结束进程。
而在非main函数中,一般使用return,因为exit直接就销毁进程了。
在main函数中,return会把main的栈给销毁掉,在回到上层调用函数,在上层调用函数里面会执行exit()函数来销毁进程。exit就不会销毁main的栈,而是直接就销毁进程。
- return 和exit
- exit和return区别
- exit和return
- exit和return
- exit()和return
- 关于exit() 和 return ()
- exit和return区别
- return 和 exit
- exit 和 return
- return和exit
- return和exit
- return和exit()
- exit和return
- Exit()和return
- exit()和_exit()和return
- Exit() 和 Return() 的区别
- exit函数和return函数
- exit()和return小析
- 一个字体的设计
- 1016. 部分A+B (15)
- 绑定Repeater实现分页获取数据
- git的基本使用
- linux下C语言基础学习笔记2
- return和exit
- 高中同学聚会有感
- ios开发——UITextView展示txt电子书时的页数调整
- lightoj1149 - Factors and Multiples【二分图最大匹配】
- x86 系列 CPU 内存寻址模式总结
- 位置无关(PIC)代码原理剖析
- JS选取DOM元素的方法
- 跨域(二级域)session共享
- 上移、下移功能