Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9463586
  • 博文数量: 1750
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 20091
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1750)

文章存档

2024年(26)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: 其他平台

2022-11-16 10:08:12


点击(此处)折叠或打开

  1. try {
  2.     // ... do something
  3.     // ... throw a exception
  4. } catch (exception &e) {
  5.     // handled the specific exception
  6. } catch (...) {
  7.     // handled other exception.
  8. }

  9. C++ 有 try / catch 用来处理异常.

  10. C提供了两个跳转函数setjmp与longjmp可以实现
  11. setjmp, sigsetjmp, longjmp, siglongjmp  - performing a nonlocal goto 即执行 非本地的 跳转.
  12. setjmp 动态建立控制稍后要跳转的目标, 而 longjmp 执行稍后的转移.
  13. setjmp()函数保存关于调用环境的各种信息(通常是堆栈指针、指令指针,可能还有其他寄存器的值) 和信号掩码)在缓冲区环境中,供longjmp()稍后使用
    longjmp()函数使用保存在env中的信息将控制转移回调用setjmp()的点,并将堆栈恢复(“倒回”)到调用setjmp()时的状态
    直接调用Setjmp()和sigsetjmp()时返回0;在longjmp()或siglongjmp()之后发生的“假”返回中,返回val中指定的非零值。
    longjmp()或siglongjmp()函数不返回


  1. #include <setjmp.h>

  2. int setjmp(jmp_buf env);
  3. void longjmp(jmp_buf env, int val)

点击(此处)折叠或打开

  1. 范例一. 演示代码的跳转在不同的函数间可以跳转. 

  2. // try / catch -->setjmp/longjmp
  3. #include <stdio.h>
  4. #include <setjmp.h>
  5.  
  6. jmp_buf env;
  7. int count = 0;
  8.   
  9. void sub_func(int idx) {
  10.     printf("sub_func --> idx :%d\n", idx);
  11.     longjmp(env, idx); // throw idx - 执行跳转到 setjmp 的那行. 并且返回"假"值 为 idx.
  12. }
  13.  
  14. int main() {
  15.  
  16.     int idx = 0;
  17.     count = setjmp(env);  //执行一遍 现场保存.
  18.     if (count == 0) { // try
  19.         printf("count : %d\n", count);
  20.         sub_func(++idx);
  21.     } else if (count == 1) { // catch(1)
  22.         printf("count : %d\n", count);
  23.         sub_func(++idx);
  24.     } else if (count == 2) { // catch(2)
  25.         printf("count : %d\n", count);
  26.         sub_func(++idx);
  27.     } else if (count == 3) { // catch(3)
  28.         printf("count : %d\n", count);
  29.         sub_func(++idx);
  30.     } else { // catch(...)
  31.         printf("other count \n");
  32.     }
  33.  
  34.     { // finally
  35.  
  36.     }
  37. }

输出结果
count:0
sub_func --> idx :1
count:1
sub_func --> idx :2
count:2
sub_func --> idx :3
count:3
sub_func --> idx :4
other count


点击(此处)折叠或打开

  1. // try / catch -->setjmp/longjmp
  2. #include <stdio.h>
  3. #include <setjmp.h>
  4.  
  5. typedef struct _Exception {
  6.     jmp_buf env;
  7.     int exceptype;
  8.  
  9. } Exception;
  10.  
  11. #define Try(excep) if ((excep.exceptype = setjmp(excep.env)) == 0)
  12.  
  13. #define Catch(excep, ExcepType) else if (excep.exceptype == ExcepType)
  14.  
  15. #define Throw(excep, ExcepType) longjmp(excep.env, ExcepType)
  16.  
  17. #define Finally
  18.  
  19.  
  20. void throw_func(Exception ex, int idx) {
  21.     printf("sub_func --> idx :%d\n", idx);
  22.     Throw(ex, idx);
  23. }
  24.  
  25. int main() {
  26.  
  27.     int idx = 0;
  28.     Exception ex;
  29.     Try(ex)// if ((excep.exceptype = setjmp(excep.env)) == 0)
  30.         printf("count : %d\n", idx);
  31.         throw_func(ex, ++idx); //longjmp(excep.env, ExcepType)
  32.     } Catch(ex, 1) { //else if (excep.exceptype == ExcepType)
  33.         printf("count : %d\n", ex.exceptype);
  34.     } Catch(ex, 2) {
  35.         printf("count : %d\n", ex.exceptype);
  36.     } Catch(ex, 3) {
  37.         printf("count : %d\n", ex.exceptype);
  38.     } Finally {
  39.         printf("Finally\n");
  40.     }
  41. }

  42. 输出结果
  43. count : 0
  44. sub_func --> idx :1
  45. count : 1
  46. Finally

点击(此处)折叠或打开

  1. 如果是多线程或者多层嵌套的情况

  2. 1)可以看到在上面的代码中,将异常定义的“帧”数据结构,然后通过函数传入栈内的方法会增加编码复杂度和代码的耦合性,这种方法不可取。有什么办法解决呢?

  3. 可以将异常帧的数据结构定义为全局。

  4. 2)多层嵌套抛出异常的情况要怎么办?

  5. 可以将每一层的异常帧传入一个定义在全局的栈数据结构中,每进入一层“Try”语句块,就创建一个新的“帧”。后续代码每抛出一个异常,就可以在全局的异常帧中pop出栈顶的帧。

  6. 每个帧之间才用链表的方式来存储。这样就达到了不需要在所有内层嵌套函数中传递栈帧的操作。

  7. 3)多线程怎么办呢?

  8. 可以利用posix中的pthread_key_t数据结构,定义每个线程的局部存储。然后利用创建,设置与获取线程局部存储数据。

  9. #include <pthread.h>
  10.  
  11. int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
  12. int pthread_setspecific(pthread_key_t key,const void *pointer));
  13. void *pthread_getspecific(pthread_key_t key);

  14. 基本使用方法是

  15. 使用 pthread_key_t 创建线程局部key并用pthread_key_create对齐初始化

  16. 后续每个线程通过pthread_setspecific与pthread_getspecific分别来设置与获取线程局部变量。

  17. 完整的测试代码如下:
  18. // try / catch -->setjmp/longjmp
  19. #include <stdio.h>
  20. #include <setjmp.h>
  21. #include <stdarg.h>
  22. #include <string.h>
  23.  
  24. #include <pthread.h>
  25.  
  26. #define ThreadLocalData pthread_key_t
  27. #define ThreadLocalDataSet(key, value) pthread_setspecific((key), (value))
  28. #define ThreadLocalDataGet(key) pthread_getspecific((key))
  29. #define ThreadLocalDataCreate(key) pthread_key_create(&(key), NULL)
  30.  
  31.  
  32. #define EXCEPTION_MESSAGE_LENGTH 512
  33.  
  34. ThreadLocalData ExceptionStack;
  35.  
  36. // Exception Flags
  37. enum {
  38.     ExceptionEntered = 0,
  39.     ExceptionThrown,
  40.     ExceptionHandled,
  41.     ExceptionFinalized
  42. };
  43.  
  44. // Exception Type
  45. typedef enum {
  46.     ExceptionTypeA = 0,
  47.     ExceptionTypeB,
  48.     ExceptionTypeC,
  49.     ExceptionTypeD
  50. } ExceptionType;
  51.  
  52. char * exceptionTable[] = {
  53.     "ExceptionTypeA",
  54.     "ExceptionTypeB",
  55.     "ExceptionTypeC",
  56.     "ExceptionTypeD"
  57. };
  58.  
  59. typedef struct _Exception {
  60.     jmp_buf env;
  61.     int line;
  62.     const char * func;
  63.     const char * file;
  64.     ExceptionType exceptype;
  65.     struct _Exception * prev;
  66.     char msg[EXCEPTION_MESSAGE_LENGTH + 1];
  67. } Exception;
  68.  
  69.  
  70. #define ExceptionPopStack() \
  71.     ThreadLocalDataSet(ExceptionStack, ((Exception*) ThreadLocalDataGet(ExceptionStack))->prev)
  72.  
  73. #define ReThrow()                ExceptionThrow(excep.exceptype, excep.func, excep.file, excep.line, NULL)
  74. #define Throw(e, cause, ...)     ExceptionThrow((e), __func__, __FILE__, __LINE__, cause, ##__VA_ARGS__, NULL)
  75.  
  76. #define Try do { \
  77.             Exception excep; \
  78.             excep.msg[0] = '\0'; \
  79.             excep.prev = (Exception*)ThreadLocalDataGet(ExceptionStack); \
  80.             ThreadLocalDataSet(ExceptionStack, &excep); \
  81.             int Exception_flag = setjmp(excep.env); \
  82.             if (Exception_flag == ExceptionEntered) { //}
  83.  
  84. #define Catch(e) \
  85.             if (Exception_flag == ExceptionEntered) ExceptionPopStack(); \
  86.         } else if (excep.exceptype == (e)) { \
  87.             Exception_flag = ExceptionHandled;
  88.  
  89. #define Finally \
  90.             if (Exception_flag == ExceptionEntered) ExceptionPopStack(); \
  91.         } { \
  92.             if (Exception_flag == ExceptionEntered) \
  93.                 Exception_flag = ExceptionFinalized;
  94.  
  95. #define EndTry \
  96.             if (Exception_flag == ExceptionEntered) ExceptionPopStack(); \
  97.         } if (Exception_flag == ExceptionThrown) ReThrow(); \
  98.         } while (0)
  99.  
  100. //
  101. void ExceptionThrow(ExceptionType e, const char * func, const char * file, int line, const char * cause, ...) {
  102.  
  103.     Exception * excep = (Exception *)ThreadLocalDataGet(ExceptionStack);
  104.     va_list ap;
  105.  
  106.     if (excep) {
  107.         
  108.         va_start(ap, cause);
  109.         vsnprintf(excep->msg, EXCEPTION_MESSAGE_LENGTH, cause, ap);
  110.         va_end(ap);
  111.  
  112.         excep->exceptype = e;
  113.         excep->func = func;
  114.         excep->file = file;
  115.         excep->line = line;
  116.  
  117.         ExceptionPopStack();
  118.         longjmp(excep->env, ExceptionThrown);
  119.     } else {
  120.         char message[EXCEPTION_MESSAGE_LENGTH+1];
  121.  
  122.         va_start(ap, cause);
  123.         vsnprintf(message, EXCEPTION_MESSAGE_LENGTH, cause, ap);
  124.         va_end(ap);
  125.  
  126.         printf("Unhandled %s: %s\n raised in %s at %s:%d\n",exceptionTable[e], message, func ? func : "?", file ? file : "?", line);
  127.     }
  128. }
  129.  
  130.  
  131. static pthread_once_t once_control = PTHREAD_ONCE_INIT;
  132.  
  133. static void init_once(void) {
  134.     ThreadLocalDataCreate(ExceptionStack);
  135. }
  136.  
  137. void ExceptionInit(void) {
  138.     pthread_once(&once_control, init_once);
  139. }
  140.  
  141. #define THREADS 50
  142.  
  143. void *thread_func(void * args) {
  144.     pthread_t selfid = pthread_self();
  145.  
  146.     // test different type exception with try catch.
  147.     Try {
  148.         Throw(ExceptionTypeA, "A");
  149.     } Catch(ExceptionTypeA) {
  150.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeA], selfid);
  151.     } EndTry;
  152.  
  153.     Try {
  154.         Throw(ExceptionTypeB, "B");
  155.     } Catch(ExceptionTypeB) {
  156.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeB], selfid);
  157.     } EndTry;
  158.  
  159.     Try {
  160.         Throw(ExceptionTypeC, "C");
  161.     } Catch(ExceptionTypeC) {
  162.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeC], selfid);
  163.     } EndTry;
  164.  
  165.     Try {
  166.         Throw(ExceptionTypeD, "D");
  167.     } Catch(ExceptionTypeD) {
  168.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeD], selfid);
  169.     } EndTry;
  170.  
  171.  
  172.     // test the control flow of try catch.
  173.     Try {
  174.         Throw(ExceptionTypeA, "A Again");
  175.         Throw(ExceptionTypeB, "B Again");
  176.         Throw(ExceptionTypeC, "C Again");
  177.         Throw(ExceptionTypeD, "D Again");
  178.     } Catch(ExceptionTypeA) {
  179.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeA], selfid);
  180.     } Catch(ExceptionTypeB) {
  181.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeB], selfid);
  182.     } Catch(ExceptionTypeC) {
  183.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeC], selfid);
  184.     } EndTry;
  185.  
  186.     // test unhandled exception.
  187.     Try {
  188.         Throw(ExceptionTypeD, "D");
  189.     } Catch(ExceptionTypeA) {
  190.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeA], selfid);
  191.     } Catch(ExceptionTypeB) {
  192.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeB], selfid);
  193.     } Catch(ExceptionTypeC) {
  194.         printf("Handled %s! %ld\n", exceptionTable[ExceptionTypeC], selfid);
  195.     } EndTry;
  196.  
  197.  
  198. }
  199.  
  200. int main() {
  201.  
  202.     ExceptionInit();
  203.  
  204.     printf("test single-thread exception!\n");
  205.     thread_func(NULL);
  206.  
  207.     printf("test multi-thread exception!\n");
  208.  
  209.     int i = 0;
  210.     pthread_t threads[THREADS];
  211.     for(i = 0; i < THREADS; i++)
  212.         pthread_create(&threads[i], NULL, thread_func, NULL);
  213.     
  214.     for(i = 0; i < THREADS; i++)
  215.         pthread_join(threads[i], NULL);
  216.     printf("test finished!\n");
  217.     return 0;
  218. }




阅读(659) | 评论(0) | 转发(0) |
0

上一篇:java 中实现 C 的数组

下一篇:华大 HC32F460

给主人留下些什么吧!~~