分享
 
 
 

kingofark's Ineffective C/C++:自白1:返回值的运用

王朝c/c++·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Ineffective C/C++ : The Confession of A Novice

《Ineffective C/C++ :一个低手的自白》

by K ][ N G of @ R K

[声明:kingofark并非高手,在论述中所举的例子未必就可取,也未必就是很好的做法。所有例子仅仅是为了说明某些问题,并不具有代表性。kingofark自知才浅,欢迎大家提出批评,指出错误。]

Item 1: Return Values

自白1:返回值的运用

[问题]:试评价如下代码碎片。

/////////////////////////////////////////////////

// ... (在外部定义中)

// 有一组函数属于同一个系统,都以 OK 或者 NG 作为返回值

#define OK 0

#define NG -1

int AFunction(); //返回OK或者NG

// ... (在某个函数中)

int Rtn; //存放调用子函数的返回值

Rtn = OK; //初始化

// ...

Rtn = AFunction(); //调用一个函数

if (Rtn == NG)

{

//...(这里做一些错误处理)

return Rtn; //只要错了就向外退

}

// ...

return Rtn; //oops! 当前函数返回

/////////////////////////////////////////////////

[kingofark的看法]:

首先需要说明的是,把返回值定成 OK、NG,以及让一组函数具有相同返回方式,这本身并非一个好主意(事实上,笔者认为这个设计很拙劣——但是,你知道,当你是一个软件工人的时候,并非什么东西都是你自己设计的),但这不是本条款所要描述的重点,因此对这些外部的背景条件我们不予讨论。

这个代码碎片至少存在三个问题:

1) 函数返回值的判断方式

/////////////////////////////////////////////////

if (Rtn == NG)

/////////////////////////////////////////////////

"if (Rtn == NG)"意味着:只要返回值不是NG,一律认为是成功。

而"if (Rtn != OK)"意味着:只要返回值不是OK,一律认为是失败。

前者意味着在子函数存在逻辑错误或者发生不可预料的错误时,子函数内部并未陷入代码编写者编写的失败执行路线导致返回NG,而这个子函数调用仍然被认为是成功的——因为此时子函数返回的很可能是OK,甚至是一个垃圾值(如果子函数内部用一个内部变量作为返回值的话),但它不等于NG!

后者附和了函数返回的意义,即只有在子函数内部确实走过了预想的正确执行路线,导致返回OK的情况下才承认调用的正确性,其它所有情况(包括函数失败返回NG以及其它任何不可预料的错误)都认为是失败——这样做的好处是:

a) 便于调试:只要在函数内部没走到过预想的执行路线,就不返回OK,于是函数调用就被认为是失败的。由此往往能够发现一些函数内部的低级逻辑错误;

b) 促使函数编写者考虑得尽量周全:如果真的是希望函数具有较高的容错性,请小心安排好返回OK。

2) 初始化的方式

/////////////////////////////////////////////////

Rtn = OK; //初始化

/////////////////////////////////////////////////

把存放函数返回值的变量初始化为成功的返回值,意味着:

a) 如果在后面的代码中没用到过这个变量,而又不小心用 "return Rtn;" 返回(从而使编译器也不会警告你这个变量没使用过),那么这个函数就会认为是成功调用的而不管其中发生了什么不可思议的事情,从而使得调试人员很难发现这个函数的问题(调试人员必须很仔细的考察与这个函数相关联的值和该函数产生的效果)。

b) 编写代码者可能是个乐观主义者。乐观是好事,但并不是说乐观就不会犯错——我们要“严肃活泼”:-)

似乎写 "Rtn = NG;" 更好一些,因为这意味着:在函数中,只要没有将 Rtn 赋值为OK,那么在后面使用 "return Rtn;" 返回时,会返回NG从而引起你的注意,看看是不是什么地方编写错了(比如忘记使用这个变量)。

3) 返回的方式

/////////////////////////////////////////////////

return Rtn; //oops! 当前函数返回

/////////////////////////////////////////////////

如果函数没有错误系统(即返回值涵盖了一系列设计好的错误码),似乎应该明确以 OK 或者 NG 返回,从而避免因为某种原因而返回垃圾值,比如

Rtn = Fun(); //误用:倒霉!Fun()恰好是一个可能返回多种错误码的函数

return Rtn; //注意:其实这样返回本身就不好!

或者

//注意:这个写法太诡异,绝对不推荐使用!仅作为举例。

return (Rtn || Flag); //笔误:惨!本来想写 | 来着(其中flag = -1)

另外,还有一个需要注意的问题:一定要根据函数的返回值判断函数调用的情况!!

这好像是一句废话,但是就有人这么做:

/////////////////////////////////////////////////

//... (在与前面相同的系统中)

int myfun()

{

if (...)

{

return 1; //一种返回情况

}

//...

return 0; //另一种返回情况

//...

}

//...(在另外一个地方的代码中)

Rtn = myfun();

if (Rtn != OK) //甚或是 if (Rtn == NG)

{

//...

}

/////////////////////////////////////////////////

是的,一般来说,我们会把诸如OK这样的东西定义为0,但如果万一不是呢?如果后来系统改版,另一个高手决定OK应该等于100呢?

上面的代码中,或许myfun()的编写者仅仅只是忘记了在注释和文档中明确说明“0与该系统中的OK对应;-1与该系统中的NG对应”并且把 "return -1;" 误写为 "return 1;",但是,请铭记:永远只使用函数明确说明的返回值进行返回值判断,无论这个值是否“(应该)实际上与某个外部量相对应”。

只要你坚持使用函数明确说明的返回值进行返回值判断,那么无论是该函数的编写者忘记了说明,还是什么其它琐事,你的做法都是对的。如果你一看,心里想,哦,应该是编写者忘了说明,“本来应该”是使用OK/NG的,所以你就这样做了,那么当OK很不幸的被重新定义为100而该函数又没有做任何更改时,写错代码的就是你。

[kingofark的收获]:

1) 宁可错杀一千,不可放过一个。

2) 只写对的,不玩鬼的。

3) 理想与现实的差距在于:理想中的错误是你想得到的,而现实中的错误有些是你想不到的。

4) 当你调程序调不通的时候,请把你自己认为最不可能出错的地方罗列出来,然后逐个仔细检查。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有