我有一个函数定义,我调用多个函数。即使其中一个函数失败,我需要继续调用其余的函数,最后返回一个错误,说明是否有任何函数调用失败。我遵循的方法是
int function foo()
{
int res, res1, res2, res3;
res1 = function1();
res2 = function2();
res3 = function3();
if (res1 == -1 || res2 == -1 || res3 == -1)
{
res = -1;
}
return res;
}
可能的另一种方法是
int function foo()
{
int res;
if (function1() == -1)
{
res = -1;
}
if (function2() == -1)
{
res = -1;
}
if (function3() == -1)
{
res = -1;
}
return res;
}
哪种方法更好? 提前谢谢。
答案 0 :(得分:8)
完全没有区别,两者都将针对相同的机器代码进行优化。偏好,可维护性,这取决于团队指导方针,偏好。
答案 1 :(得分:3)
优先考虑,使代码正确。这比可读性和优化更重要。
这意味着你需要考虑函数在它调用的函数都成功的情况下应返回的内容。
对于此问题的许多答案会更改返回的结果,或者如果“子功能”全部成功,则可能会返回失败指示。你需要注意不要这样做。
就我个人而言,我认为你的第一个选项的整体形式非常好 - 它清楚地表明无论一个或多个子功能是否失败,都会调用3个子功能。一个问题是如果所有这些函数都成功,它会返回一个不确定的结果。
警惕使用按位或结合结果的答案 - 至少存在2个潜在问题:
正如John Marshall在几条评论中指出的那样,评估的顺序是不确定的。这意味着如果您只是按位串起函数调用 - 或者可以按任何顺序调用函数。如果函数之间没有排序依赖关系,这可能不是问题,但通常有 - 特别是如果您不关心返回值,除了成功/失败指示符(如果您没有使用返回值,那么调用该函数的唯一原因是它的副作用)
如果函数成功时可以返回正,非零值,那么测试失败就比检查结果或者是否为非零一样有点棘手。
考虑到这两个潜在的问题,我认为没有理由尝试做比选项1(或第二个选项)更好的事情 - 只需确保将res
设置为成功值(0?)没有任何子功能失败的情况。
答案 2 :(得分:2)
怎么样:
int foo ()
{
bool failed = false;
failed |= (function1() != 0);
failed |= (function2() != 0);
failed |= (function3() != 0);
return failed? -1 : 0;
}
您还可以将三个调用折叠为一个表达式,并完全省略failed
变量(以可读性为代价):
int foo ()
{
return ((function1() != 0) | (function2() !=0 ) | (function3() != 0))? -1 : 0;
}
我喜欢function1
function2
和function3
具有相同签名的第一种方法,因为我可以将它们放在函数指针表中并循环遍历条目,这使得添加{{ 1}}很容易。
答案 3 :(得分:1)
如果您可以定义关于返回值的任何精确约定,您可以简单地使用按位或:
int foo() {
if (function1() | function2() | function3())
return -1;
else
return 0;
}
答案 4 :(得分:1)
我更喜欢第二种方法。如果你想要单行,你可以做一些像......
char success = 1;
success &= (foo() == desired_result_1);
success &= (bar() == desired_result_2);
等
答案 5 :(得分:1)
第二种是“更好”的方法。但是,如果没有随意携带指标变量,我会更多:
if( function2() == -1 ){
return -1;
}
建议 :(没有魔术数字)
我也不会像你使用它那样使用“魔法数字”。代替:
if( check_fail( function2() ) ){
return FAILED;
}
更清楚地说明了你的想法。意图更容易维护。魔术数字有时会伤到你。例如,我认识的金融人员无法理解为什么花费“$ -1.00”的交易导致他们的申请表现异常。
答案 6 :(得分:1)
在第一种形式中,在完成所有3个呼叫之前,您不会检查状态。我认为这表明你的意图最清楚。第二种形式更接近于更常见的情况,如果检测到错误,则提前返回。
无论如何,这都是一个微妙的事情。你不应该在互联网上问我们陌生人,你应该问你团队的其他人,因为他们是那些必须忍受它的人。
答案 7 :(得分:0)
您使用按位运算符来创建一个不需要临时变量的“整洁”变体,并且具有其他花哨性(使用更高级的运算符):return func1()|func2();
(这与使用逻辑或,|相同) |)。但是,如果您需要检查被调用者中的特定函数,则可以创建一个位集:return func1() << 1 | func2();
(这假定它们返回1或0)
答案 8 :(得分:0)
我也会投票给第二个。
这个问题让我想起了我在一个表单验证项目中所做的类似的事情。
我传入一个空字符串的引用。对于我想要检查的每个条件,我要么在字符串中添加一行文本,要么我没有。如果在每次测试后字符串仍为空,则没有错误,我继续处理表单。否则,我将字符串打印为消息框(描述问题),并要求用户修复错误。
在这种情况下,我并不关心错误是什么,只是是错误。哦,作为奖励,我的验证代码会记录一些,因为用户看到的错误就在那里。
答案 9 :(得分:0)
如果需要在某处重用结果,请使用局部变量。另外,打电话和比较。
答案 10 :(得分:0)
我之前看过这样的代码可能会更清洁一点:
bool result = true;
result = function1() == -1 && result;
result = function2() == -1 && result;
result = function3() == -1 && result;
return result?-1:0;
编辑:忘记了短路。
答案 11 :(得分:0)
int foo() {
return function1() | function2() | function3();
}
答案 12 :(得分:0)
另一个选择:将指向状态变量的指针传递给每个函数,并且只有在出现错误时才让函数设置它。
void function1(int *res)
{
bool error_flag = false;
// do work
if (error_flag && (res != NULL)
{
*res = ERROR;
}
}
// similar for function2, function3, ...
int foo()
{
int res = OK;
function1(&res);
function2(&res);
function3(&res);
return res;
}
答案 13 :(得分:0)
由于所有3个函数总是必须首先调用,然后才关心结果,我会选择第一个解决方案,因为语句的顺序反映了这一点。对我来说似乎更清楚。另外,我通常不喜欢在if子句中返回一个值(即有副作用)的函数,但这是个人偏好。
答案 14 :(得分:0)
这听起来像是丰富的Perl习语的工作“&lt;尝试某事&gt; || die()”。
int foo(){
int retVal = 0;
function1()!= -1 || retval = -1;
function2()!= -1 || retval = -1;
function3()!= -1 || retval = -1;
// ...
返回retVal;
}
答案 15 :(得分:0)
我这样写:
int foo()
{
int iReturn = 0;
int res1 = function1();
if (res1 == -1)
{
return iReturn;
}
int res2 = function2();
if (res2 == -1)
{
return iReturn;
}
int res3 = function3();
if (res3 == -1)
{
return iReturn;
}
return res;
}
作为编码规则,您应该将变量声明为靠近使用它的位置。
最好使用像res1,res2,res3这样的中间变量。 但是选择一个好的名称,这样当您从函数中获取值时,您的意图就会清晰。
请注意,在您给我们的示例中,您从未分配过成功时可能会返回的int res;
。编码规则是尽快初始化变量。
因此,您还应该无限制地初始化res1
res2
res3
。
返回未初始化的值会导致未定义的行为。