我认为以下代码是正常的(并且malloc / free类似):
int foo(){
FILE *fp = fopen("test.in", "r");
int i;
for(i = 0; i < NUM; i ++){
if(Match(fp, i)){
fclose(fp);
return i;
}
}
fclose(fp);
return 0;
}
我们可以看到fclose(fp)
在代码中出现两次。如果函数foo中有其他return语句,它会显得更多。但是,我必须多次写fclose(fp)
很麻烦。一种解决方案只是一个函数的一个返回。但是,多次返回有时是有用的。还有其他解决方案吗?
PS:据我所知,lisp中有一个宏(带有打开文件)。
(with-open-file (stream-var open-argument*)
body-form*)
它可以为我们打开和关闭文件。
答案 0 :(得分:7)
使用break
通常有助于:
int foo() {
FILE *fp = fopen("test.in", "r");
int i, result;
result = 0;
for(i = 0; i < NUM; i ++){
if(Match(fp, i)){
result = i;
break;
}
}
fclose(fp);
return result;
}
答案 1 :(得分:6)
在linux内核的源代码中,有许多函数需要在返回时处理锁和其他资源。它们通常在函数末尾添加一个清理标签,并在每次早期返回时添加goto
。我个人推荐这种用法以避免重复代码,也许这是goto
唯一合理的用法。
答案 2 :(得分:3)
额外的间接层可以确保您不会错过函数的退出:
int foo(FILE *fp)
{
int i;
for(i = 0; i < NUM; i ++){
if(Match(fp, i)){
return i;
}
}
return 0;
}
int foo_wrapper(void)
{
FILE *fp = fopen("test.in", "r");
int out = foo(fp);
fclose(fp);
return out;
}
答案 3 :(得分:1)
我将通过goto扩展异常处理(在@Charles Peng的回答中提到):
你这样做:
int func(...)
{
...
f = fopen(...);
if (f == NULL) {
log("failed opening blah blah...");
goto err;
}
...
m = malloc(...)
if (m == NULL) {
log("blah blah...");
goto err_close_f;
}
...
if (do_something(...) < 0) {
log("blah blah...");
goto err_close_f;
}
...
r = alloc_resource(...)
if (r == 0) {
log("blah blah...");
goto err_free_m;
}
...
return 0;
err_free_m:
free(m);
err_close_f:
fclose(f);
err:
return -1;
}
这样做的好处是它非常易于维护。使用这个习语时,资源获取和释放有一些对称的外观。此外,资源释放超出了主要逻辑,避免了最令人烦恼的过度混乱。检查函数的错误处理是否正确是非常简单的(只需检查它是否跳转到适当的点,以及前一个标签是否释放任何获取的资源)......
答案 4 :(得分:1)
不在函数末尾的return语句相当于goto语句。尽管某些函数看起来好像有多个return语句,但是在保持各种代码库的同时,我的经验是每个函数只有1个退出点的代码库更容易维护。