免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4307 | 回复: 12
打印 上一主题 下一主题

[C] 给C语言加上很酷的异常处理机制 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-12-04 12:41 |只看该作者 |倒序浏览
很多人都说C缺少异常机制,用长跳机制只能简单模仿异常,下面我给出一个笔者实现的C异常处理机制,支持语法类似:

try
{
    ...
}
catch( type1 )
{
}
catch( type2 )
{
}
....
finally
{
}

也就是支持平行catch和finally的异常处理机制,当然也支持嵌套。

下面我将分别给出 h和c文件,诸位先别插楼。

下面的代码出自CUA(C language Util Assembly  C语言工具集),是我实现的一套C语言基础库。

论坛徽章:
0
2 [报告]
发表于 2014-12-04 12:41 |只看该作者
  1. #ifndef __CUA_EXCEPT_H__
  2. #define __CUA_EXCEPT_H__

  3. #include "base.h"
  4. #include <setjmp.h>


  5. typedef bool (* cua_exception_match_t)( u_long , u_long );

  6. typedef
  7. struct cua_exception_info
  8. {
  9.         struct cua_exception_info *prev;
  10.         jmp_buf                    jmp;

  11.     /// 0: try; 1: throwed; 2: caugth; 3: re-throw; +4: finally
  12.     int                        state;
  13.     u_long                     clss;
  14.         long                       code;
  15.     unichar const             *info;
  16. }
  17. cua_exception_info;


  18. extern  bool    __cua_except_begin( cua_exception_info * );
  19. extern  int     __cua_except_end( cua_exception_info * );
  20. extern  bool    __cua_except_catch( cua_exception_info * , u_long , cua_exception_match_t );
  21. extern  bool    __cua_except_finally( cua_exception_info * );
  22. extern  int     __cua_except_throw( u_long , long , unichar const * );



  23. #define __cua_except_begin__           {\
  24.                                          cua_exception_info _local_except_info_;\
  25.                                          CVERIFY(__cua_except_begin(&_local_except_info_));\
  26.                                          if(setjmp(_local_except_info_.jmp) == 0)

  27. #define __cua_except_catch__(clss, match)       else if(__cua_except_catch(&_local_except_info_, (u_long)(clss), (match)))

  28. #define __cua_except_finally__                  if(__cua_except_finally(&_local_except_info_))

  29. #define __cua_except_end__               __cua_except_end(&_local_except_info_); }



  30. #define __cua_except_code__      (_local_except_info_.code)
  31. #define __cua_except_class__     (_local_except_info_.clss)
  32. #define __cua_except_info__      (_local_except_info_.info)
  33. #define __cua_except_throw__(c, n)      do { if(c) __cua_except_throw((u_long)(c), (long)(n), _ctext("FILE:") _ctext(__FILE__) _ctext(" (") _ctext(_mtext(__LINE__)) _ctext(")")); CUA_TEST(_ctext("__cua_except_throw__") && false); } while(0)



  34. #endif

复制代码

论坛徽章:
0
3 [报告]
发表于 2014-12-04 12:42 |只看该作者
下面是实现:
  1. #include "file.h"

  2. #ifdef _CUA_MT
  3. #   include "mt.h"
  4. #endif

  5. #include "except.h"
  6. #include <assert.h>
  7. #include <stdlib.h>
  8. #include <stdio.h>


  9. #ifdef _CUA_MT
  10. static u_long  __s_cua_exception_tvi;
  11. #else
  12. static cua_exception_info *__s_cua_exception = NULL;
  13. #endif


  14. #ifdef _CUA_MT
  15. static cua_exception_info *__get_current()
  16. {
  17.         cua_exception_info *p;
  18.         __cua_thread_get_variable(__s_cua_exception_tvi, &p);
  19.         return p;
  20. }

  21. static bool __set_current( cua_exception_info *p )
  22. {
  23.         return __cua_thread_set_variable(__s_cua_exception_tvi, p);
  24. }

  25. #else
  26. static cua_exception_info *__get_current()
  27. {
  28.         return &__s_cua_exception;
  29. }

  30. static bool __set_current( cua_exception_info *p )
  31. {
  32.         __s_cua_exception = p;
  33.         return true;
  34. }
  35. #endif


  36. int __cua_except_init()
  37. {
  38. #ifdef _CUA_MT
  39.         __s_cua_exception_tvi = __cua_thread_variable_alloc();
  40. #endif
  41.     return 0;
  42. }

  43. int __cua_except_uninit()
  44. {
  45.     return 0;
  46. }


  47. bool __cua_except_begin( cua_exception_info *p )
  48. {
  49.     p->state = 0;
  50.         p->clss = 0;
  51.         p->code = 0;
  52.     p->info = 0;
  53.         p->prev = __get_current();
  54.     return __set_current(p);
  55. }

  56. int __cua_except_end( cua_exception_info *p )
  57. {
  58.     __set_current(p->prev);
  59.     if(p->state < 4)
  60.         p->state += 4;

  61.     if(p->state == 1 + 4 || p->state == 3 + 4)
  62.         __cua_except_throw(p->clss, p->code, p->info);

  63.     return 0;
  64. }

  65. int __cua_except_throw( u_long clss, long cd, unichar const *txt )
  66. {
  67.         cua_exception_info *p;
  68.     if(!clss) {
  69.         CUA_PANIC(_ctext("__cua_except_throw class 0"));
  70.         return -1;
  71.     }
  72.    
  73.     p = __get_current();
  74.         if(!p) {
  75.                 unichar buff[512];
  76.                 __cua_sprintf(buff, 512, _ctext("unhandled cua exception (%u, %ld) %s\n"), clss, cd, txt);
  77.                 CUA_PANIC(buff);
  78.                 return -1;
  79.         }

  80.     CASSERT(p->state != 1);
  81.     if(p->state == 0)
  82.         p->state = 1;
  83.     else if(p->state >= 4)
  84.         p->state = 4 + 3;
  85.     else
  86.         p->state = 3;

  87.         p->clss = clss;
  88.         p->code = cd;
  89.     p->info = txt;
  90.         longjmp(p->jmp, 1);
  91.     return 0;
  92. }

  93. bool __cua_except_catch( cua_exception_info *p, u_long clss, cua_exception_match_t match )
  94. {
  95.     if(p->state != 1)
  96.         return false;
  97.    
  98.     if(match ? match(clss, p->clss) : (clss == 0 || clss == p->clss)) {
  99.         p->state = 2;
  100.         return true;
  101.     }
  102.     return false;
  103. }

  104. bool __cua_except_finally( cua_exception_info *p )
  105. {
  106.     if(p->state >= 4)
  107.         return false;

  108.     p->state += 4;
  109.     return true;
  110. }
复制代码

论坛徽章:
26
处女座
日期:2016-04-18 14:00:4515-16赛季CBA联赛之深圳
日期:2020-06-02 10:10:5015-16赛季CBA联赛之广夏
日期:2019-07-23 16:59:452016科比退役纪念章
日期:2019-06-26 16:59:1315-16赛季CBA联赛之天津
日期:2019-05-28 14:25:1915-16赛季CBA联赛之青岛
日期:2019-05-16 10:14:082016科比退役纪念章
日期:2019-01-11 14:44:062016科比退役纪念章
日期:2018-07-18 16:17:4015-16赛季CBA联赛之上海
日期:2017-08-22 18:18:5515-16赛季CBA联赛之江苏
日期:2017-08-04 17:00:4715-16赛季CBA联赛之佛山
日期:2017-02-20 18:21:1315-16赛季CBA联赛之天津
日期:2016-12-12 10:44:23
4 [报告]
发表于 2014-12-04 12:44 |只看该作者
酷个毛 恶心的要死

论坛徽章:
0
5 [报告]
发表于 2014-12-04 12:48 |只看该作者
代码中出现的测试宏  CVERIFY  CASSERT CUA_TEST , CUA_PANIC 你可以直接删掉,或者替换为assert

但是删CVERIFY时要保留被测代码,你应该懂的。

CUA_PANIC 是系统灾难停止函数,你可以替换为任何你喜欢的方式。

这个实现要用到的一个关键技术是,线程本地存储,如果没定义_CUA_MT宏,那么就假定为单线程模式,就会用一个全局变量来替代线程本地存储。


下面是测试代码:
  1. static
  2. void test1()
  3. {
  4.     __cua_except_begin__
  5.     {
  6.         __cua_except_begin__
  7.         {
  8.             __cua_throw__(20, 0);
  9.         }
  10.         __cua_catch__(10, 0)
  11.         {
  12.             printf("in catch 10 %u\n", __cua_except_class__);
  13.         }
  14.         __cua_catch__(20, 0)
  15.         {
  16.             printf("in catch 20 %u\n", __cua_except_class__);
  17.             __cua_throw__(2, 0);
  18.         }
  19.         __cua_finally__
  20.         {
  21.             printf("in finally 1\n");
  22.         }
  23.         __cua_except_end__
  24.     }
  25.     __cua_catch__(2, 0)
  26.     {
  27.         printf("in catch 2 %u\n", __cua_except_class__);
  28.         __cua_throw__(10, 0);
  29.     }
  30.     __cua_finally__
  31.     {
  32.         printf("in finally 2\n");
  33.         __cua_throw__(2, 0);
  34.     }
  35.     __cua_except_end__
  36.    
  37. }

  38. static
  39. void test()
  40. {
  41.     __cua_except_begin__
  42.     {
  43.             test1();
  44.     }
  45.     __cua_catch__(1, 0)
  46.     {
  47.         printf("in catch 1\n");
  48.     }
  49.     __cua_except_end__
  50. }
复制代码

论坛徽章:
6
酉鸡
日期:2013-11-04 15:30:02巳蛇
日期:2014-01-23 10:36:23双鱼座
日期:2014-01-23 13:08:332015亚冠之鹿岛鹿角
日期:2015-09-03 14:36:002015亚冠之武里南联
日期:2015-09-18 10:48:1315-16赛季CBA联赛之山西
日期:2016-05-05 00:05:33
6 [报告]
发表于 2014-12-04 14:37 |只看该作者
这啥啊?一坨一坨的
太菜了,没看懂

论坛徽章:
0
7 [报告]
发表于 2014-12-04 14:48 |只看该作者
回复 4# evaspring

用起来很爽就可以了
比如:

char *p = malloc(100);

__cua_except_begin__
{
       .......
}
__cua_except_finally__
{
      free(p);
}
__cua_except_end__


这样可以保证free掉p,

如果没有这个语义,你要在每个异常出口加free。

   

论坛徽章:
0
8 [报告]
发表于 2014-12-04 14:49 |只看该作者
回复 6# Dannysd


    异常处理语义嘛,很难理解吗?

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
9 [报告]
发表于 2014-12-04 19:30 |只看该作者
这个好像有人用宏做过了, 反正都不好
如果我
try{
return;
}finally{
....
}

你就S B了

论坛徽章:
0
10 [报告]
发表于 2014-12-04 19:38 来自手机 |只看该作者
呃。。。c++的异常处理都没人用,应该更没人在c里面用异常处理了吧。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP