本文共 1831 字,大约阅读时间需要 6 分钟。
异常指的是在程序运行过程中发生的异常事件,通常是由硬件问题或者程序设计问题所导致的。在Java等面向对象的编程语言中异常属于对象。
这是百度百科的引用,现代编程大部分都实现了异常机制,而早期语言比如C语言是没有异常机制的,需要程序员根据每个函数的返回值来判断程序是否正常,这样会带来下面这些问题
异常的出现就是为了解决这样的问题,使得程序员能够从重复的异常处理中解放出来,同时提高了程序的安全性。
熟悉C语言的小伙伴们对这个函数可能不陌生,这相当于C语言里的try/catch(当然很多人也把他称之为全局的goto),事实上C语言也确实有不少宏封装了类似try/catch结构的宏定义。这两个函数的使用也非常简单
// 全局的jmp_bufjmp_buf g_jmp_buf;void exception_f() { // 逻辑不对 longjmp(g_jmp_buf, 1); // 1是错误码,这里程序会中断,返回到setjmp的地方 // longjmp的原理也比较简单,熟悉汇编的同学可能比较熟悉,jmp_buf记录了所有寄存器信息 // longjmp的时候就是恢复所有寄存器状态,pc寄存器也重新指向setjmp的地址}void normal_f() { // no exception}void foo() { int ret = setjmp(g_jmp_buf); if (0 == ret) { // 正常流 normal_f(); exception_f(); } else { // 异常流 // ret是异常错误码 }}
介绍玩了大概的使用方法,下面再简单聊一聊longjmp的原理。为了方便理解,我在这里引用TCC编译器中的源码
// tcc-0.9.25 win32/include/setjmp.h/* * The buffer used by setjmp to store the information used by longjmp * to perform it's evil goto-like work. The size of this buffer was * determined through experimentation; it's contents are a mystery. * NOTE: This was determined on an i386 (actually a Pentium). The * contents could be different on an Alpha or something else. */#define _JBLEN 16#define _JBTYPE inttypedef _JBTYPE jmp_buf[_JBLEN];/* * The function provided by CRTDLL which appears to do the actual work * of setjmp. */int _setjmp (jmp_buf);#define setjmp(x) _setjmp(x)/* * Return to the last setjmp call and act as if setjmp had returned * nVal (which had better be non-zero!). */void longjmp (jmp_buf, int);
这段代码只能在i386上运行,而且只有jmp_buf和宏定义,正如代码中注释表明的,实际上的实现在CRTDLL中,但是jmp_buf定义以及可以让我们一窥究竟。
setjmp实际上是把CPU的和程序执行相关的寄存器(比如pc寄存器,栈寄存器等)的值存放到内存中,等到程序调用longjmp的时候,再从jmp_buf中把值恢复到寄存器里面,这样CPU就可以回到setjmp时的状态,也就能实现所谓的“非本地跳转”了。转载地址:http://mtuws.baihongyu.com/