return, exit, _exit的区别
2015-11-24 21:21
495 查看
return是返回的最常用的方式
_exit属于POSIX定义的系统调用
exit是GLIBC封装之后的函数
1 _exit和exit都会导致整个进程退出,清理进程所占用的资源,但是glibc封装exit函数的时候加了一些功能:比如提供了在结束程序时回调的接口(atexit), flush 缓冲区(系统调用是没法做这个的
,因为像printf, scanf之类的缓冲区都属于应用层缓冲区,内核清理资源自然无法顾及)
2return 会清理函数栈,另外两个就不会了,如果是最后一个线程return,也会像exit那样清理资源并flush缓冲区,这一点可以通过一段代码观察一下:
这里可以发现,只有按照return 方式返回局部变量a的析构函数才能得到调用,因为exit _exit都是不清理函数栈的.
一般这不会有什么问题,因为资源都回收了,栈空间自然也没了.但是对于约定在函数返回时调用的函数就没法调用了.
还有一点要注意的是,全局变量并不在栈空间里面,对于C++的情形而言,可以在全局变量的构造函数中申请资源然后
在程序结束的时候由析构函数释放.这个过程事实上是通过在函数启动的时候插入全局变量的构造函数,函数退出的地方插入
析构函数做到的.所以,即使是调用exit,全局变量仍旧可以正常析构. 但是_exit就不一样了,仍旧不会释放(_exit属于系统
调用,它只管内核空间中的一些资源释放)
3关于vfork的问题
这是apue上面的一段示例代码,很惊奇的发现居然可以在子进程中访问到局部变量var,这意味着什么??要知道单一进程内
,如果出现函数调用,过程是这样的:
1返回地址压栈
2参数压栈
3保存当前的ebp
在程序中写一个return意味着什么???思考一下,其实是要清理当前的函数栈的,C语言的情形下比较好想,反正栈指针退到指定位置就好
c++中却还要在返回之前调用局部变量的析构函数
最最重要的是,即使是像c语言那样简单的将栈指针回退,在vfork的情形下,也会出问题:
回退到哪??前面已经说过了,返回地址处(也就是当前函数的调用点)!
可以想象,这里所说的在父进程空间运行多么图省事,连一个单独的函数调用的开销都不肯付出(如果有子过程调用,那局部变量不可能访问得到)
直接就用了父进程main函数的函数栈, 你一个return,它直接把栈指针指到了main函数调用点,简单来说,就是main函数的函数栈被清理了,那切换到父进程就莫名奇妙了!
而如果是exit或_exit,则进程直接退出了,对于用户空间的函数栈根本不理会(具体来说就是ebp, esp寄存器的值)
所以不会出现问题.
_exit属于POSIX定义的系统调用
exit是GLIBC封装之后的函数
1 _exit和exit都会导致整个进程退出,清理进程所占用的资源,但是glibc封装exit函数的时候加了一些功能:比如提供了在结束程序时回调的接口(atexit), flush 缓冲区(系统调用是没法做这个的
,因为像printf, scanf之类的缓冲区都属于应用层缓冲区,内核清理资源自然无法顾及)
2return 会清理函数栈,另外两个就不会了,如果是最后一个线程return,也会像exit那样清理资源并flush缓冲区,这一点可以通过一段代码观察一下:
#include<iostream> #include<unistd.h> using namespace std; class A { public: A(){ cout << "constructor" << endl; } ~A(){ cout << "distructor" << endl; } }; void func(int i) { A a; if(i == 0) _exit(-1); else return; } int main() { func(1); return 0; }
这里可以发现,只有按照return 方式返回局部变量a的析构函数才能得到调用,因为exit _exit都是不清理函数栈的.
一般这不会有什么问题,因为资源都回收了,栈空间自然也没了.但是对于约定在函数返回时调用的函数就没法调用了.
还有一点要注意的是,全局变量并不在栈空间里面,对于C++的情形而言,可以在全局变量的构造函数中申请资源然后
在程序结束的时候由析构函数释放.这个过程事实上是通过在函数启动的时候插入全局变量的构造函数,函数退出的地方插入
析构函数做到的.所以,即使是调用exit,全局变量仍旧可以正常析构. 但是_exit就不一样了,仍旧不会释放(_exit属于系统
调用,它只管内核空间中的一些资源释放)
#include<iostream> #include<unistd.h> using namespace std; class A { public: A(){ cout << "constructor" << endl; } ~A(){ cout << "distructor" << endl; } }; void func(int i) { A a; if(i == 0) _exit(-1); else return; } A ta; int main() { A a; _exit(0); }
3关于vfork的问题
#include<unistd.h> #include<stdio.h> int glovalvar = 9; int main() { int var = 88; pid_t pid; printf("before vfork\n"); if((pid = vfork()) < 0) { fprintf(stderr, "vfork error"); return 0; } else if(pid == 0) { glovalvar++; var++; _exit(0); } else { } printf("pid = %ld, glob=%d, var=%d\n", (long)getpid(), glovalvar, var); return 0; }
这是apue上面的一段示例代码,很惊奇的发现居然可以在子进程中访问到局部变量var,这意味着什么??要知道单一进程内
,如果出现函数调用,过程是这样的:
1返回地址压栈
2参数压栈
3保存当前的ebp
在程序中写一个return意味着什么???思考一下,其实是要清理当前的函数栈的,C语言的情形下比较好想,反正栈指针退到指定位置就好
c++中却还要在返回之前调用局部变量的析构函数
最最重要的是,即使是像c语言那样简单的将栈指针回退,在vfork的情形下,也会出问题:
回退到哪??前面已经说过了,返回地址处(也就是当前函数的调用点)!
可以想象,这里所说的在父进程空间运行多么图省事,连一个单独的函数调用的开销都不肯付出(如果有子过程调用,那局部变量不可能访问得到)
直接就用了父进程main函数的函数栈, 你一个return,它直接把栈指针指到了main函数调用点,简单来说,就是main函数的函数栈被清理了,那切换到父进程就莫名奇妙了!
而如果是exit或_exit,则进程直接退出了,对于用户空间的函数栈根本不理会(具体来说就是ebp, esp寄存器的值)
所以不会出现问题.
相关文章推荐
- 利用百度API获取当前用户的省市地区,适合定位精度要求不高的项目
- CC254X按键流程
- codeforces 593A 2char
- python 查询数据库数据 NoneType报错
- 电力载波芯片ST7538Q调试记录1
- 路由协议默认管理距离
- Maven创建web工程详解
- NOIP2015总结
- 财经专栏
- 判断两多项式之积是否等于另一多项式
- 泛型
- iOS客户端,微信,bug 通知栏点击失效,且无法删除。
- gdb常用的调试方法
- hdu 5199 Gunner(STL之map,水)
- 进程 进程句柄 进程ID
- ubuntu12.04.5安装openssh-server所引发的血案
- 线性同余方程模板( A+C*x=B(mod D) )
- 课程设计之第二次冲刺—11.24第一天
- .net之母版页应用所需要注意的几个点
- Android jni开发资料--NDK环境搭建