在使用C编程的时候,为了保证程序的稳壮性,通常需要对函数调用的返回值做充分的处理。但是这样会带来一些别的副作用,例如代码的可阅读性很差,很大一部分代码用来处理错误。参考驱动代码里面,采用了较多了goto语句,不过还是有蛮多的返回值判断。曾经看到过一份为某个模块代码,里面处理的方式比较巧妙:
int foo(void) { int ret = 0; ret |= xxx_module_do_a(ret, x, y); ret |= xxx_module_do_b(ret, xxx, ddd); ret |= xxx_module_do_c(ret, k, i, l); ret |= xxx_module_do_d(ret, o, p, q); if ( ret != 0) { //处理具体的错误 } return x; } //模块函数里面这样处理ret int xxx_module_do_a(int ret, x, y) { if ( ret != 0 ) { return ret; } ret |= do_something(); return ret; }
通过位域来标识不同的错误码,将上一个模块函数调用返回的错误码传入下一个函数调用,如果发现有错误,立即返回。到最后面集中处理错误码,这样虽然带来了一定的函数调用开销,但是可阅读性大大提高了。其实这个处理方式相当于goto语句的处理方式,只是把返回值判断的那句分散到了每个模块函数里面,并且goto不会带来调用开销。
请问各位,你们都有什么样的处理方法,分享一下。
C的话,你的foo函数其实做的差不多了。
但是C++的话,其实可以参考boost.asio的方式,关键函数都有异常版本和返回值版本。
以connect函数为例:
1. boost::asio::connect( basic_socket< Protocol, SocketService > & s, Iterator begin, boost::system::error_code & ec )
2. boost::asio::connect ( basic_socket< Protocol, SocketService > & s, Iterator begin )
如果你不想要异常抛出,你必须申明一个error_code,这个算是一个你需要做异常处理的提醒。老实说,return的话,很容易被忽略。
如果你真要忽略error_code也可以,如果有问题就抛一个异常,这个异常你可以在一个地方集中处理,并且主逻辑可以只写成功的case非常的清晰易读,但是异常要用好的话,也有蛮多的学问,比如对象的生命周期的管理,已经操作的回滚等等。。。
个人的话,会倾向于使用版本1.
C++不太熟悉,还是高级语言机制完善些。