如何确保 malloc/free fopen/fclose 匹配?

发布于 2024-11-15 10:18:20 字数 589 浏览 0 评论 0原文

我认为下面的代码是正常的(和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)。

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

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

I think the following code is normal (and malloc/free is similar):

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

As we can see fclose(fp) appears twice in the code. It will appear more if there are other return statements in the function foo. However, it is troublesome that I have to write fclose(fp) many times. One solution is just one return for one function. However, multiple returns is sometimes useful. Is there any other solution?

PS: As I know, there is a macro(with-open-file) in lisp.

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

It could open and close file for us.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

枕梦 2024-11-22 10:18:20

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

The use of break often helps:

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;
}
夏の忆 2024-11-22 10:18:20

在Linux内核的源代码中,有许多函数必须在返回时处理锁和其他资源。他们通常在函数末尾添加一个清理标签,并在发生提前返回时转到那里。我个人推荐这种用法以避免重复代码,也许这是 goto 唯一合理的用法。

In the source code of linux kernel, there are many functions that have to take care of locks and other resource on return. And they conventionally add a cleanup label at the end of the function, and goto there whenever early return occurs. I personally recommend this usage to avoid duplicate code, and maybe this is the only sane usage of goto.

无敌元气妹 2024-11-22 10:18:20

额外的间接层可以确保您不会错过函数的退出:

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

An extra layer of indirection can ensure you don't miss an exit from the function:

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;
}
假装不在乎 2024-11-22 10:18:20

我将通过 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;
}

这样做的优点是它非常易于维护。使用此惯用语时,资源获取和释放具有某种对称的外观。此外,资源释放不在主要逻辑之外,避免了最令人烦恼的过度混乱。检查函数的错误处理是否正确是非常简单的(只需检查它是否跳转到适当的点,以及前一个标签是否释放了任何获取的资源)...

I'll expand on exception handling via goto (mentioned in @Charles Peng's answer):

You do it something like:

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

The advantage of this is that it's very maintainable. Resource acquisition and release has a somewhat symmetrical look when using this idiom. Also, resource release is out of the main logic, avoiding excessive clutter where it annoys the most. It's quite trivial to check that error handling of functions is right (just check that it jumps to the appropiate point, and that the previous label releases any acquired resource)...

淡水深流 2024-11-22 10:18:20

不在函数末尾的 return 语句相当于 goto 语句。尽管看起来有些函数使用多个 return 语句会更简单,但根据我在维护各种代码库时的经验,每个函数只有 1 个退出点的代码库更容易维护。

A return statement NOT at the end of a function is the equivalent of a goto statement. Even though it may appear as though some functions are simpler with multiple return statements it has been my experience while maintaining various code bases that the ones with only 1 exit point from every function are easier to maintain.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文