杭州达内嵌入式培训火热招生中。。。|杭州达内c++培训火热招生中
您现在的位置: 杭州达内 >>C/C++>>杭州达内C++培训:如何用C语言模拟C++的异常处理机制
杭州达内C++培训:如何用C语言模拟C++的异常处理机制
杭州达内 - C/C++ 来源:未知 发布时间:2014-02-13 11:27

  想学会如何用C语言模拟C++的异常处理机制吗?今天杭州达内技术小编就为大家详细的分析一下过程,供大家参考:
   起因:在c语言工程代码当中,常常要处理各种关于异常的处理,每次当程序比较复杂的时候,就必须用好几个if来嵌套使用,比如

  if (xxx)

  {

  if(xxx)

  {

  }

  else

  {

  return ERR_NO;

  }

  }

  这样的代码显得非常混乱,也不容易管理。

  由于c的工程当中一般错误都有专有的错误列表,所以在这边,在我们的机制里我只添加了关于错误Id的异常捕捉处理。

  达内小编思路分析:

  首先,我使用了#define来将c当中没有的关键词替代,比如try,catch,throw,先想到的是用return,break之类的c语言当中先有的关键词来模拟,这就有了我的个版本:

  #ifndef EXCEPTION_H

  #define EXCEPTION_H

  // 一个不成熟的exception机制

  typedef unsigned int ERR_TYPE;

  #define NO_ERR 0

  static ERR_TYPE err; //try-catch-throw错误处理机制

  #define try do

  #define catch(N) while(0);if(N>=NO_ERR)

  #define throw(N) err=N;break;

  #define throwAgain(N) err=N;return;

  #endif

  调用实例代码:

  void f(void)

  {

  try

  {

  throw(6);

  }

  catch(err)

  {

  throwAgain(err);

  }

  }

  int main()

  {

  try

  {

  f();

  }

  catch(err)

  {

  printf(“%d”, err);

  }

  }

  这个设计的程序有一个很大的问题,那就是它只能在同级的函数下使用try.

  这是什么意思呢?如果我需要这样使用:

  Int main()

  {

  Try

  {

  f();

  }

  catch(err)

  {

  printf(“%d”, err);

  }

  }

  Void f()

  {

  G();

  // some codes follows

  }

  Void g()

  {

  Throw(3);

  }

  在g()throw出异常3的时候,main函数没有办法直接捕捉,而是必须在f()函数下面继续执行后面的语句。就是这套设计的机制多个嵌套的函数是没有办法实施的。

  那么还有什么办法可以解决这个问题呢?Goto可以吗?不可以,goto也只能在同级的函数下使用。goto是本地的:它只能跳到所在函数内部的标号上,而不能将控制权转移到所在程序的任意地点 .

  较后找到一个方法:

  #include
int setjmp(jmp_buf env)

  Returns: 0 if called directly, nonzero if returning from a call to longjmp.

  void longjmp(jmp_buf env, int val);

  setjmp 和longjmp这2个函数可以在不同的函数进行跳转,只要设置他们的上下文,在用longjmp跳转到这设置好的上下文当中就可以了!!

  这2个函数的使用方法:

  #include
#include
jmp_buf ebuf;

  void f2(void);

  int main(void)

  {

  int i;

  printf(“1”);

  i=setjmp(ebuf);

  if(i==0)

  {

  f2();

  printf(“This will not be printed.”);

  }

  printf(“%d”,i);

  return 0;

  }

  void f2(void)

  {

  printf(“2”);

  longjmp(ebuf,3);

  }

  首先,在函数a里面setjmp,将当前函数的env都存储起来,然后在函数b里面调用longjmp,这样就会直接跳转到函数a的setjmp这个地方,longjmp的第二个值作用是在第二次返回a函数的时候setjmp会返回longjmp的第二个参数。

  有了这个方法,我们的程序就好设计多了,由于设计多个函数的调用,所以设计的时候使用了链表来处理保存每个函数的env.

  全部实现代码如下:

  #ifndef LIST_H

  #define LIST_H

  typedef struct list_head_tag

  {

  struct list_head_tag *prev;

  struct list_head_tag *next;

  }list_head;

  #define list_for_each(pos, head) \

  for ( pos = (head)->next; \

  pos != (head); \

  pos = pos->next)

  #define list_for_each_safe(pos,pos_next,head) \

  for ( pos = (head)->next, pos_next = pos->next; \

  pos != (head); \

  pos = pos_next, pos_next = pos->next)

  #define list_empty(head) (head->next == head)

  #define list_entry(ptr, type, member) ((type*)ptr)

  #define init_list_head(ptr) \

  do{\

  (ptr)->prev = ptr; \

  (ptr)->next = ptr; \

  }while(0)

  extern void list_add_before(list_head *node, list_head *pos);

  extern void list_add_after(list_head *node, list_head *pos);

  extern void list_del(list_head *node);

  #endif

  #include “list.h”

  void list_add_before(list_head *node, list_head *pos)

  {

  node->prev = pos->prev;

  node->next = pos;

  pos->prev->next = node;

  pos->prev = node;

  }

  void list_add_after(list_head *node, list_head *pos)

  {

  node->prev = pos;

  node->next = pos->next;

  pos->next->prev = node;

  pos->next = node;

  }

  void list_del(list_head *node)

  {

  node->prev->next = node->next;

  node->next->prev = node->prev;

  }

  #ifndef EXC_H

  #define EXC_H

  char err = -1;

  static char isJumpListInit = 0;

  //jmp_buf jump_buffer;

  typedef struct JumpBufListTag

  {

  struct list_head_tag list;

  jmp_buf jump_buffer;

  }JumpBufList, *JumpBufListPtr;

  JumpBufList jumplist = {NULL, NULL};

  JumpBufListPtr head = &jumplist;

  JumpBufListPtr cur = &jumplist;

  int SetCurJump(void)

  {

  JumpBufListPtr newPtr = (JumpBufList*)calloc(sizeof(JumpBufList));

  if (!isJumpListInit)

  {

  init_list_head(&head->list);

  isJumpListInit = 1;

  }

  list_add_after(&newPtr->list, &head->list);

  cur = newPtr;

  return 0;

  }

  void JumpCurLong(void)

  {

  longjmp(cur->jump_buffer, 1);

  }

  void DestoryCurJumpEnv( void )

  {

  list_del(&cur->list);

  free(cur);

  cur = head->list.next;

  }

  #define try SetCurJump();if(setjmp(cur->jump_buffer) == 0)

  #define catch(N) DestoryCurJumpEnv();if(N>=0)

  #define throw(N) err=N;JumpCurLong();

  #endif

  这边,List.h和list.c摘抄自linux内核代码。

  使用demo代码:

  void h()

  {

  throw(7);

  }

  void e()

  {

  h();

  }

  void g(void)

  {

  try

  {

  e();

  printf(“g()3”);

  }

  catch(err)

  {

  throw(err);

  }

  }

  int main()

  {

  try

  {

  g();

  }

  catch(err)

  {

  printf(“%d”, err);

  }

  return 0;

  }

  这样,就可以实现一个简易版本的用c语言模拟c++的错误处理异常的机制了。
    (如果需要更多的关于C方面的技术内容请访问达内培训C技术论坛学习)
 


相关标签:杭州达内C++培训(2)
 达内简介 达内就业 达内课程 联系我们 网站导航
杭州达内为上软件有限公司 Copyright @ 2007-2012 版权所有 苏ICP备10118953号-1
分享到: