C语言实现类似JAVA的异常处理,需用用到标准库中的setjmp.h。
在导入了setjmp.h之后,我们就可以利用里面定义的类型jmp_buf来设置锚点,也就是可能会出现异常的位置,相当于java的try。
jmp_buf结构体里面存放了寄存器的状态,setjmp(buf)在第一次执行的时候一定是返回0,int setjmp(jmp_buf envbuf)。跟他配合使用的是longjmp(jmp_buf envbuf,int value)。
当可能出现异常时,我们可以用if(0 == setjmp(buf))设置一个锚点,将异常处理的代码放到else里面。
if(0 == setjmp(buf))
{
//可能出现异常的代码
}
else
{
//异常处理代码
}
当出现异常是,我们用longjmp(buf,value),这样程序将会还原buf里面的环境,程序又会回到if条件判断,但是这次0 == setjmp(buf)一定为假,所以执行的异常处理代码。
longjmp的第二个参数如果设成0,会自动变为1。所以setjmp()只有第一次设置锚点时才有可能返回0。通过longjmp的第二个参数,我们可以判断异常的类型。
下面的code就是用了enum表示异常的类型,将异常处理单独提出作为一个函数。
另外需要注意的是,没一个锚点必须单独声明一个jmp_buf类型的变量,也就是说jmp_buf变量是不能共享使用的。java中的throw固定是返回上一个锚点,但是在C里面,返回到哪个锚点是码农说了算的,所以用的时候要慎重,建议不要做出longlongjmp()这样的跳转。
#include<stdio.h>
#include<setjmp.h>
#define TRY(buf,exp) exp = setjmp(buf);if(exp == 0)
#define CATCH else
#define THROW(buf,exp) longjmp(buf,exp)
//every try has a jmp_buf
jmp_buf buf;
jmp_buf buf_f;
void f();
void g();
//we use a enum to represent all exceptions
typedef enum exp
{
none,
exp_main,
exp_f,
exp_g
}EXP;
EXP exp_kind;
void exception(EXP exp_kind)
{
switch (exp_kind)
{
case exp_main:
printf("world\n");
break;
case exp_f:
printf("from f()\n");
break;
case exp_g:
printf("form g()\n");
break;
default:
printf("this is default!!!\n");
}
}
int main()
{
exp_kind = none;
TRY(buf,exp_kind)
{
printf("Hello,");
f();
}
CATCH
{
printf("this is main exception\n");
exception(exp_kind);
}
}
void g()
{
THROW(buf_f,exp_g);
}
void f()
{
exp_kind = none;
TRY(buf_f, exp_kind)
{
g();
}
CATCH
{
printf("this f() exception\n");
exception(exp_kind);
}
}