2011-06-14 72 views
2

我认为下面的代码是正常的(和的malloc/free是相似的):如何确保malloc/free fopen/fclose匹配?

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中有其他返回语句,它会显得更多。但是,我不得不多次写fclose(fp)。一个解决方案只是一个函数的返回。但是,多重回报有时是有用的。还有其他解决方案吗?

PS:据我所知,在lisp中有一个宏(with-open-file)。

(with-open-file (stream-var open-argument*) 
    body-form*) 

它可以为我们打开和关闭文件。

回答

6

在Linux内核源代码,有要照顾锁和其他资源的回报率上的许多功能。而且他们通常在函数的末尾添加一个清理标签,并在那里提前返回。我个人推荐此用法以避免重复的代码,也许这是goto唯一明智的用法。

+0

我认为当函数非常大时使用'goto'会更好。 – lisper 2011-06-14 06:21:43

+1

我认为最好不要使功能非常大。 – 2011-06-14 11:52:32

+0

@波佩尔森:确实如此。保持功能小于screenful真的有帮助。 – 2011-06-14 13:28:21

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; 
} 
+0

这是做到这一点的方法 - 使用变量来存储你的状态,并相应地指导你的程序执行。 – thelionroars1337 2011-06-14 04:17:30

+0

是的,它的工作原理。如果代码有两个循环,它看起来会很难看,因为我应该设置另一个状态来指示内部循环终止。 – lisper 2011-06-14 06:02:06

+0

井,不一定: '为(I = 0; I dja 2011-06-14 06:17:02

2

额外的间接层可以保证你不从功能错过一个出口:

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; 
} 
+0

这是一个好方法。 – lisper 2011-06-14 06:39:54

+1

是的,只是给他们有意义的名字,你会全部设置 – CAFxX 2011-06-14 06:57:08

1

我将通过例外处理转到扩大(在@Charles彭的答复中提到):

你这样做是这样的:

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; 
} 

这样做的好处是,它是非常维护。使用这个习惯用法时,资源获取和释放有一个对称的外观。另外,资源释放不在主要逻辑之中,避免过度混乱,最容易受到干扰。检查函数的错误处理是否正确(只是检查它跳转到适当的点,并且以前的标签释放任何获取的资源)是非常简单的...

+0

谢谢。许多文章说'goto'应该在代码中消失,现在我想'goto'会出现在我的代码中。 :) – lisper 2011-06-15 02:56:05

+0

@lisper - yep,使用正确的工具来完成这项工作。就我个人而言,我一直认为应该有另一种形式的'goto',它仅限于函数范围(比如'skip')。 – detly 2011-06-15 06:17:42

+0

@detly你的意思是说goto标签和goto应该在同一个函数中吗? (PS:它已经在c标准中。) – lisper 2011-06-15 08:09:50

1

返回语句不在函数的结尾相当于goto语句。即使它看起来好像某些函数对于多个返回语句更简单一样,但在维护各种代码库时,我的经验是,每个函数只有一个出口点的代码很容易维护。

相关问题