这篇讲的不错:
http://blog.csdn.net/smstong/article/details/50728022
首先Active Record
然后EBP,ESP等指针
2 通过setjmp和longjmp操纵AR,完成任意跳转
setjmp/longjmp主要从嵌套的函数调用中跳出来。
#include <stdio.h> #include <setjmp.h> jmp_buf jb; void a(); void b(); void c(); int main() { if(setjmp(jb)==0){ a(); } printf("after a(); "); return 0; } void a() { b(); printf("a() is called "); } void b() { c(); printf("b() is called "); } void c() { printf("c() is called "); longjmp(jb, 1); }
3 C语言中模拟异常处理
为了统一处理错误,C++,C#,Java等现代语言引入了异常处理机制。C里面模拟异常的代码大概如下:
#include <stdio.h> #include <stdlib.h> #include <setjmp.h> jmp_buf jb; void f1() { printf("进入f1() "); if(0/*正确执行*/){ } else { longjmp(jb,1); } printf("退出f1() "); } void f2() { printf("进入f2() "); if(1/*正确执行*/) { } else { longjmp(jb, 2); } printf("退出f2() "); } int main() { int r = setjmp(jb); if(r==0){ f1(); f2(); }else if(r==1){ printf("处理错误1 "); exit(1); }else if(r==2){ printf("处理错误2 "); exit(2); } return 0; }
可以推测,
- throw要负责两件事情:(1)完成跳转;(2)恢复堆栈AR;
- try则负责保存当前AR
4 不要在C++中使用setjmp和longjmp
因为,longjmp的时候,不保证局部对象析构函数的调用。
longjmp()跳转前局部对象可能并不会析构(g++),也可能析构(VC++),C++标准对此并无明确要求。这种依赖于具体编译器版本的代码是应该避免的。
而C++本身的throw关键字,却能严格保证局部对象构造和析构的成对调用。
5 辩证看待异常处理
已经存在大量没有严格使用异常处理C++函数库和类库,兼容的C库更是没有异常的概念,历史的包袱让C++很难完全采用异常处理。在这个方面,Java和C#从头开始,重要的库都实现了标准的异常处理规范,完全采用异常机制切实可行。
有趣的是C++11在标准中删除了异常规范,而且添加了 noexcept关键字来声明一个函数不会抛出异常,可见异常并不是那么受欢迎。
然而,C++的STL广泛使用异常,所以实际上使用了STL的C++程序是不可能禁用异常的,要是没有了STL,C++又有什么优势了呢?C++在不断的矛盾冲突中向前发展者。