C语言异常与断言接口的实现
作者:网络转载 发布时间:[ 2015/8/31 13:18:09 ] 推荐标签:测试开发技术 C语言
上面的代码没有提供嵌套的处理程序,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);
}
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南