我想知道是否有更好的方法来处理C中的情况,只要在一系列表达式中遇到错误就要退出函数。 (在这种情况下,它是一个在出错时返回NULL的函数)
e.g。在某些C代码中,他们试图通过将一系列语句与AND(&&)相结合来缩短错误处理。
return doSomething() &&
doSomething2() &&
doSomething3() && ... ;
这让我感到恼火,因为我们在一行声明中将塞进一行。但我想替代方案是
if (!(value = doSomething()))
return NULL;
if (!(value = doSomething2()))
return NULL;
etc
return value;
但是我在perl和bash脚本中看到的短路错误评估呢。
int die(int retvalue) {
exit(retvalue);
}
.....
(value = doSomething()) || die(1);
(value = doSomething2()) || die(2);
(value = doSomething3()) || die(3);
return value;
这个问题的主要问题是RHS必须是一个表达式,所以你不能真正转到函数或从函数返回。有人会发现这个有价值的还是太有限了?
编辑:我想我应该在第一个例子中包含换行符。问题是如果你决定在中间添加另一个表达式,你需要小心。
答案 0 :(得分:5)
我已经看到在C中使用GOTO就是出于这个目的。
因为在C中没有'finally'结构,所以即使你提前退出函数,也需要一种释放所有内存的方法。
所以它基本上如下 (如果我错了,有人可以纠正我的C语法,我有点生疏了)
int foo()
{
/* Do Stuff */
if(!DoSomething())
GOTO Failure;
if(!DoSomething2())
GOTO Failure;
if(!DoSomething3())
GOTO Failure;
/* return success */
return true;
Failure:
/* release allocated resources */
/* print to log if necessary */
return false;
}
重要提示 不要将GOTO用于执行流程。它们只应在出错时使用,并且只能转到当前函数的末尾。如果你将它们用于其他任何事情,你就会创造出可能破坏现实结构的意大利面条代码。只是不要这样做。
修改强>
正如其中一张海报所指出的那样,使用Exit(x)将会终止整个程序,从而保留该解决方案以防止致命错误。然而,您在一条线上的原始提出的解决方案(DS()& DS2()& DS3())对于错误处理提出了问题。
如果要将函数包装在某种特定于函数的错误处理中,则在将函数调用全部包装在一行中时无法执行此操作。所以,至少你可以做一些像
这样的事情int result1 = 0;
int result2 = 0;
int result3 = 0;
result1 = DoSomething();
if(result1)
result2 = DoSomething2();
if(result2)
result3 = DoSomething3();
return result1 && result2 && result3;
因为这种方法不会妨碍错误处理。
答案 1 :(得分:4)
如果您唯一的担忧是在一条线上塞满太多,那么为什么不使用:
return doSomething()
&& doSomething2()
&& doSomething3()
&& ... ;
我倾向于将第二种情况写成:
if (!(value = doSomething())) return NULL;
if (!(value = doSomething2())) return NULL;
: : : : :
return value;
(甚至排列返回以使其可读)因为我喜欢在屏幕上看到尽可能多的代码(并且您可以根据需要在行之间插入其他检查)。
答案 2 :(得分:1)
这样的事情怎么样?
int result;
result = doSomething();
result = result && doSomething2();
result = result && doSomething3();
return result;
这使用与第一个示例类似的方式进行短路,但它允许您将其分成多行并添加注释等。
答案 3 :(得分:0)
我建议不要使用您提出的技术。首先,C中的退出终止了该过程;它不仅仅是回报。所以它仅限于少数致命错误。
在我看来,你试图避免的第一个解决方案是最好和最容易理解的。
答案 4 :(得分:0)
根据我的经验,用C语言写这个的惯用方法是用一系列if语句来启动函数,该语句检查函数其余部分的前置条件。如果不满足前提条件,则立即返回错误代码。这样,当你到达函数体的主要部分时,你知道一切都很好,并且可以使代码尽可能简单。
换句话说,你是第二种方法。
作为一个例子,可以编写一个函数来复制字符串,如下所示:
int copy_string(char *source, char *target, size_t max)
{
if (source == NULL)
return -1;
if (target == NULL)
return -1;
source_len = strlen(source);
if (source_len + 1 > max) // +1 for NUL
return -1;
memcpy(target, source, source_len + 1);
return 0;
}
(我喜欢为错误返回-1的Unix系统调用约定,但这是一个有争议的问题,与这个问题无关。)
答案 5 :(得分:0)
我之前见过这个:
int Function (void)
{
int Result = DoSomething();
if (Result) Result = DoSomething2();
if (Result) Result = DoSomething3();
if (Result) Result = DoSeomthing4();
return Result;
}
它看起来很整洁,易于对齐。它不会立即退出,但它不会执行任何其他操作。这当然假设函数在成功时返回非零值。否则,如果函数在失败时返回非零,则可以简单地使用if (!Result)
。