上面的代码没有提供嵌套的处理程序,Allocation_handle标志的使用也很麻烦。
  把Allocation_Failed变成一个异常,该异常是在malloc返回一个空指针时由allocate引发:
  Except_T Allocate_Failed = {"Allocation failed"};
  void *allocate(unsigned n)
  {
  void *new = malloc(n);
  if(new)
  return new;
  RAISE(Allocation_Failed);
  assert(0);
  }
  如果客户调用程序代码想处理这个异常,那么它需要在TRY-EXCEPT语句内调用allocate:
  extern Except_T Allocate_Failed;
  char *buf;
  TRY
  buf = allocate(4096);
  EXCEPT(Allocate_Failed)
  fprintf(stderr, "could't allocate the buff ");
  exit(EXIT_FAILURE);
  END_TRY;
  TRY-EXCEPT语句是用setjmp和longjmp来实现的
  TRY-FINALLY语句的语法是:
  TRY
  S
  FINALLY
  S1
  END_TRY
  如果S没有产生任何异常,那么执行S1,然后继续执行END_TRY,如果S产生了异常,那么S的执行被中断,控制立即转给S1。S1执行完后,引起S1执行的异常重新产生,使得它可以由前一个实例化的处理程序来处理。注意:S1是在两种情况中都必须执行的,处理程序可以用RERAISE宏指令显示地重新产生异常
  #define RERAISE Except_raise(Except_frame.exception,
  Except_frame.file, Except_frame.line)
  接口中的后一个宏指令是:
  #define RETURN switch (Except_stack = Except_stack->prev,0) default: return
  RETURN宏指令用在TRY语句的内部,用来代替return语句
  实现
  Except接口中的宏指令和函数一起维护了一个记录异常状态以及实例化处理结构的堆栈。结构中的字段env是setjmp和longjmp使用的某个jmp_buf,这个堆栈可以处理嵌套的异常
  typedef struct Except_Frame Except_Frame;
  struct Except_Frame {
  Except_Frame *prev;
  jmp_buf env;
  const char *file;
  int line;
  const T *exception;
  };
  extern Except_Frame *Except_stack;
  Except_stack指向异常栈顶的异常帧,每个帧的prev字段指向它的前一帧,产生一个异常是将异常的地址存在exception字段中,并分别在file和line字段中保存异常的附属信息–异常产生的文件以及行号
  TRY从句将一个新的Except_Frame压入异常栈,并调用setjmp,由RAISE和RERAISE调用Except_raise填充栈顶帧的字段exception、file和line,从异常栈中弹出栈顶Exception_Frame,然后调用longjmp,EXCEPT从句检查该帧中的exception字段,决定应该用哪个处理程序。FINALLY从句执行清除代码,并重新产生已弹出的异常帧中存储的异常。
  宏指令TRY、EXCEPT、ELSE、FINALLY_TRY一起将TRY-EXCEPT语句转化成如下形式的语句:
  do {
  creat and push an Except_Frame
  if(first return from setjmp) {
  S
  } else if (exception is e1) {
  S1
  ……
  } else if (exception is en) {
  Sn
  } else {
  S0
  }
  if(an exception occurrend and wasn’t handled)
  RERAISE;
  } while(0)
  Exception_Frame的空间分配很简单,在由TRY开始的do-while主体中的复合语句内部声明一个该类型的局部变量即可:
  #define TRY do {
  volatile int Except_flag;
  Except_Frame Except_frame;
  Except_frame.prev = Except_stack;
  Except_stack = &Except_frame; 
  Except_flag = setjmp(Except_frame.env);
  if (Except_flag == Except_entered) {
  在TRY语句内有四种状态,由下面的枚举标识符给出
  enum { Except_entered=0, Except_raised,
  Except_handled,   Except_finalized };
  setjmp的第一个返回值将Except_flag设置为Except_entered,表示进入TRY语句,并且将某个异常帧压入异常栈,Except_entered必须为0,因为setjmp首次调用的返回值为0,随后,setjmp的返回值将被设为Except_raised,表示发生了异常,处理程序将Except_flag的值设成Except_handled,表示处理程序已经对异常进行了处理。
  #define TRY do {
  volatile int Except_flag;
  Except_Frame Except_frame;
  Except_frame.prev = Except_stack;
  Except_stack = &Except_frame; 
  Except_flag = setjmp(Except_frame.env);
  if (Except_flag == Except_entered) {
  #define EXCEPT(e)
  if (Except_flag == Except_entered) Except_stack = Except_stack->prev;
  } else if (Except_frame.exception == &(e)) {
  Except_flag = Except_handled;
  #define ELSE
  if (Except_flag == Except_entered) Except_stack = Except_stack->prev;
  } else {
  Except_flag = Except_handled;
  #define FINALLY
  if (Except_flag == Except_entered) Except_stack = Except_stack->prev;
  } {
  if (Except_flag == Except_entered)
  Except_flag = Except_finalized;
  #define END_TRY
  if (Except_flag == Except_entered) Except_stack = Except_stack->prev;
  } if (Except_flag == Except_raised) RERAISE;
  } while (0)
  后实现代码如下:
  #include <stdlib.h>
  #include <stdio.h>
  #include "assert.h"
  #include "except.h"
  #define T Except_T
  #ifdef WIN32
  __declspec(thread)
  #endif
  Except_Frame *Except_stack = NULL;
  void Except_raise(const T *e, const char *file,
  int line) {
  Except_Frame *p = Except_stack;
  assert(e);
  if (p == NULL) {
  fprintf(stderr, "Uncaught exception");
  if (e->reason)
  fprintf(stderr, " %s", e->reason);
  else
  fprintf(stderr, " at 0x%p", e);
  if (file && line > 0)
  fprintf(stderr, " raised at %s:%d ", file, line);
  fprintf(stderr, "aborting... ");
  fflush(stderr);
  abort();
  }
  p->exception = e;
  p->file = file;
  p->line = line;
  Except_stack = Except_stack->prev;
  longjmp(p->env, Except_raised);
  }