现代编程语言,基本都提供了 try...catch 语法,用于进行程序逻辑的异常处理。
为什么要用 try...catch?
我们来看一下常规的程序写法:
int biz_xxx(...) {
// step1: do logic1
....
if (ret != 0) {
// 错误处理1
...
}
// step2: do logic2
...
if (iret != 0) {
// 错误处理2
...
}
// step3: do logic3
...
if (iret != 0) {
// 错误处理3
...
}
......
}
复制代码
从上面的代码,我们可以看出,正常的业务处理过程中,每个步骤都会判断是否失败,如果失败,则进行相应的错误处理,每种错误的处理代码可能有所不同。这样,正常的业务流程,与错误处理的代码混杂在一起。在一个大型软件中,业务正常逻辑处理和错误处理都可能非常复杂,代码量也可能很大,这样混杂在一起后,业务正常的逻辑主线非常不清晰,代码阅读起来比较困难。
因此,一些更为强大的编程语言,都提供了 try ... catch 语法,将正常业务流程与异常处理分开,使得代码的可阅读性、可理解性大大提高。
采用 try ... catch 语法,程序的写法变为:
int biz_xxx(...) {
try {
// step1: do logic1
....
// step2: do logic2
...
// step3: do logic3
...
} catch (exception1) {
// 错误处理1
} catch (exception1) {
// 错误处理2
} catch (others) {
// 错误处理3
}
}
复制代码
看看,这样是不是代码阅读起来非常清晰了!
C 语言本身并不支持 try ... catch 这样的语法。但我们可以使用 C 语言的宏功能,自定义几个宏,用 goto 语句和函数内 Label 进行跳转,从而实现函数内 try ... catch 这样的写法。
宏定义如下:
#define TRY(condition) \
do { \
if (!(condition)) goto FINISH_LABEL; \
} while(0)
#define TRY_THROW(condition, exception_name) \
do { \
if (!(condition)) goto exception_name; \
} while(0)
#define THROW(exception_name) goto exception_name;
#define CATCH(exception_name) \
goto FINISH_LABEL; \
exception_name:
#define FINALLY \
FINISH_LABEL:
复制代码
用以上宏,编写业务代码,示例如下:
int biz_xxx(...) {
int fd = -1;
int read_len = 0;
int write_len = 0;
// step1: do logic1
TRY((fd = open(...)) != -1);
....
// step2: do logic2
TRY_THROW((read_len = read(fd, ....)) >= 0, READ_ERROR);
...
// step3: do logic3
TRY_THROW((write_len = write(fd, ....)) > 0, WRITE_ERROR);
...
CATCH(READ_ERROR) {
// 错误处理1
}
CATCH(WRITE_ERROR) {
// 错误处理2
}
FINALLY {
// ....
}
}
复制代码
这种写法,将正常业务逻辑与错误处理分开,使得代码非常清晰,易于维护!
我的微信号是 实力程序员,欢迎大家关注我。
评论