现代编程语言,基本都提供了 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 { // .... }}
复制代码
这种写法,将正常业务逻辑与错误处理分开,使得代码非常清晰,易于维护!
我的微信号是 实力程序员,欢迎大家关注我。
评论