如何确保malloc/free fopen/fclose匹配?
我认为以下代码是正常的(malloc/free也是类似的):如何确保malloc/free fopen/fclose匹配?,c,fopen,C,Fopen,我认为以下代码是正常的(malloc/free也是类似的): 它可以为我们打开和关闭文件。使用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
它可以为我们打开和关闭文件。使用
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;
}
intfoo(){
文件*fp=fopen(“test.in”,“r”);
int i,结果;
结果=0;
对于(i=0;i
在linux内核的源代码中,有许多函数必须在返回时处理锁和其他资源。他们通常会在函数的末尾添加一个清理标签,并且每当出现提前返回时,goto
。我个人建议使用此用法以避免重复代码,也许这是唯一明智的使用goto
额外的间接层可以确保您不会错过退出函数的机会:
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;
}
intfoo(文件*fp)
{
int i;
对于(i=0;i
我将通过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;
}
int func(…)
{
...
f=fopen(…);
如果(f==NULL){
日志(“打开失败等等…”);
后悔莫及;
}
...
m=malloc(…)
如果(m==NULL){
日志(“废话…”);
转到错误关闭;
}
...
如果(做某事(…)<0){
日志(“废话…”);
转到错误关闭;
}
...
r=分配资源(…)
如果(r==0){
日志(“废话…”);
去犯错误;
}
...
返回0;
无错误:
自由(m);
错误关闭错误:
fclose(f);
错误:
返回-1;
}
这样做的好处是它非常易于维护。使用此习惯用法时,资源获取和发布的外观有些对称。此外,资源释放超出了主要逻辑,避免了最烦人的过度混乱。检查函数的错误处理是否正确(只需检查它是否跳到适当的点,以及之前的标签是否释放了任何获取的资源)是非常简单的。不在函数末尾的return语句相当于goto语句。尽管看起来有些函数使用多个返回语句更简单,但我在维护各种代码库时的经验是,每个函数只有一个退出点的代码库更容易维护。这就是实现方法-使用变量存储状态,并相应地指导程序的执行。是的,它是有效的。如果代码有两个循环,它看起来会很难看,因为我应该设置另一个状态来指示内部循环终止(i=0;iIt适用于此代码。如果您不知道
结果的值会怎么样?如果您不能做一个简单的测试,那么是的,您需要添加状态变量或使用goto。我认为当函数非常大时使用goto
会更好。我认为最好不要使函数非常大。@Bo Persson:inded、 保持函数小于屏幕真的很有帮助。是的,只要给它们起一个有意义的名字,你就会明白了。谢谢。许多文章说,goto
应该在代码中消失,现在我想goto
会出现在我的代码中。:)@lisper-是的,使用正确的工具来完成这项工作。我个人一直认为应该有另一种形式的goto
,它只限于功能范围(比如,跳过)。@你的意思是说goto标签和goto
应该在同一个功能中吗?(注:它已经在c标准中了。)@lisper-是的,总是这样。我不知道标准中有这样的限制,但是-我从来没有在我写的任何东西中使用过goto
(虽然我在微处理器引导加载程序代码中使用了“长跳转”,但这是实现定义的行为)@lisper-heh,我刚检查过,你说得对!这段时间,我一直不知道这是一个实际的限制。
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;
}
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;
}