关于“函数针对入参判空并返回”

有人在博文中写出程序流程: 

main( ) {    init(); //初始化    

while(1)    {         

step1: 从系统消息队列中取一个消息        

step2: 将消息发给指定任务处理    

 } } 

每个任务的处理流程如下: 

xx_task_process( *msg )  

{        

step1: 分析消息类型     

step2: 调用对应的处理流程     

step3: 向系统消息队列发送消息     

return;     

       他是想说,每个任务的处理是互相独立的,如果有判空返回的防御,可让软件不崩溃,仅仅忽略一个任务的执行而已,将影响降到最低。

但是实际的电信设备类软件(嵌入式软件)真的这么简单吗?真的可以做到完美的防御所有入参为空指针的情况吗?我觉得大部分软件,包括电信设备类软件(嵌入式软件),不大可能做到完美防御;

同时,这类防御的成本太高,就算做到了,那成本也太大了,大到让我们不如不做这种防御。 

       作者写出的流程只是最上层的处理消息的流程,看上去好像很单纯,各个消息的处理很容易做到互相独立。但是我们要理解的是,要想真正的做到在任何判空的地方返回,完美地忽略掉任务,是非常难得。

因为有个叫副作用的东西。如果这个任务在返回之前没有产生副作用,那只要注意返回时不产生副作用就行;如果在返回前已经产生副作用,我们为了完美的忽略掉这个任务,还需要消除之前产生的副作用。

这非常难!要想做到任意一个判断返回都完美地忽略掉任务,基本不可能,就算做到了,那成本也太大了。 
       有人可能会说,既然在任意函数中判空返回,完美地忽略掉任务很难,那我们就看着办吧,碰运气,能做到完美最好,做不到,留下副作用也无所谓。这里就要说到留下副作用的危害了:带病运行

最终导致问题的爆发点跟案发第一现场相差十万八千里。带病运行危害太大,应该尽量避免。 
       有人可能会说,我不滥用还不行吗,我只在某些函数中使用判空返回。针对这个,我想说两点:1.你必须保证完美防御   2.你需要考虑完美防御的成本是否太高。事实上,我认为这类防御手段不应该成为一种常用的防御手段。

我倾向于把这类防御手段看做是缓兵之计:暂时规避问题,保证不崩溃,减少损失;同时,赶紧找出问题根源,解决之。 

       我强烈反对滥用甚至强制在每个函数里面使用这类防御。很遗憾,我司有的项目组好像有这样的规定。用屁股想想就知道,他们虽然在每个函数里面防御了,但是肯定没有做到完美防御,就是他们的代码可能会带病运行

同时,额外增加了很多成本: 1.每个函数开始处都要写这种恶心的判断代码   2.每个函数的返回值都被错误码占用了  3.每个调用函数的地方必须判断返回值,然后可能会做一些处理,但是我可以肯定,他们不可能做到完美防御。 

4.不完美的防御导致带病运行,最终导致问题难以定位。 

PS1:        有人列出了目前三大烂规定:1.函数针对入参判空并返回  2.代码里面写修改记录  3.判断语句常量放左边 


PS2:        文中提到“ 事实上,我认为这类防御手段不应该成为一种常用的防御手段。我倾向于把这类防御手段看做是缓兵之计:暂时规避问题,保证不崩溃,减少损失;同时,赶紧找出问题根源,解决之。

简单说,我的观点是谨慎酌情使用,不能滥用,我倾向于主要作为缓兵之计使用。 
       如果能做到完美防御(完美的忽略这次执行,不产生副作用。具体效果来说可以是无坏的影响或者将坏的影响降低。并且执行效果必须是确定的,不能是随机的),并且防御成本相对较低,那完全是可以做的呀,我没有反对。

同时要注意到,这篇文章的讨论仅仅针对函数针对入参判空并返回这个具体问题。这种问题往往是不能做到完美防御,或者很难做到完美防御的(成本很大)。 
       当然,如果你在某些点确实做到了完美防御并且相对成本较低,性价比很高,那当然是OK的。但是我相信,这样的点不会很多。如果你很多地方采用了这种防御,我有理由相信:1.有些点你没做到完美防御 2.你花的成本很大 如果防御是不完美的,

然后在那祈祷运气好,期望最终执行是无坏的影响或者坏的影响降低,那只能祝你好运了。鉴于不完美的防御导致带病运行,导致问题难定位,我觉得尽量不要使用不完美的防御。 


PS3:        这次讨论的问题非常具体,就是函数针对入参判空并返回,不要泛化、上升,不然没法讨论了。针对这个问题我相信这篇博文表述的已经相当全面,请仔细全部阅读完再参与讨论。 

 

原文地址:https://www.cnblogs.com/towik/p/3199683.html