我观察到成功完成方法预期功能的一般编码约定为0.(如exit(0)所示)。
这种让我感到困惑的原因是,如果我的if语句中的方法和方法返回0,则“if condition”为false,从而敦促我思考方法失败了一分钟。当然我知道我必须附加一个“!” (如if(!Method())),但这种惯例不是自相矛盾的吗?
答案 0 :(得分:15)
您需要区分错误代码和错误标志。代码是表示任意数量错误的数字,而标志是表示成功的布尔值。
说到错误代码,我们的想法是:只有一种方法可以成功,但有许多方法可以失败。将0作为一个好的单一唯一编号,代表成功,然后你有其他所有数字是一种表示失败的方式。 (任何其他方式都没有意义。)
当谈到错误标志时,这个想法很简单:True表示它有效,false表示没有。您通常可以通过其他方式获取错误代码,并采取相应的行动。
某些功能使用错误代码,有些使用错误标记。没有什么令人困惑或倒退的事情,除非你试图将一切都视为旗帜。并非所有的返回值都是一个标志,这只是你必须习惯的东西。
请记住,在C ++中,您通常会处理异常错误。您只需从捕获的异常中获取必要的信息,而不是查找错误代码。
答案 1 :(得分:3)
这个惯例并不矛盾,它与你对函数的期望使用相矛盾。
其中一个必须改变,它不会成为惯例; - )
我通常会写:
if (Function() == 0) {
// code for success
} else {
// code for failure
}
或if (Function() != 0)
与案例相反。
整数可以隐式转换为布尔值,但这并不意味着你总是应该。 0
此处表示0
,并不代表false
。如果你真的想,你可以写:
int error = Function();
if (!error) {
// code for success
} else {
// code for failure, perhaps using error value
}
答案 2 :(得分:0)
有各种约定,但C函数最常见的是失败时返回0,成功时返回正值,这样你就可以在if
语句中使用它(几乎所有的CPU都有条件跳转,可以测试一个值是否为0这就是为什么在C中这个“被滥用”,0表示错误,其他一切都意味着真实。)
另一个惯例是在错误时返回-1,而在成功时返回其他一些值(尤其是使用POSIX函数设置errno
变量时)。这就是0可以解释为“成功”的地方。
然后是exit
。它是不同的,因为返回的值不是由C解释,而是由shell解释。在这里,值0
表示成功,而其他每个值都表示错误条件(许多工具会告诉您此值发生了什么类型的错误)。这是因为在shell中,通常只有0-127的范围用于返回有意义的值(历史原因,它是无符号字节,127以上的所有内容都意味着被某些信号IIRC杀死)。
答案 3 :(得分:0)
您已将问题标记为[c]
和 [c++]
。这是什么?因为答案会有所不同。
你说:
我观察到成功完成方法预期功能的一般编码约定是0。
对于C,这很好。
对于C ++,它肯定是而不是。 C ++有另一种发出失败信号的机制(即异常)。滥用(数字)返回值通常是设计不良的标志。
如果由于某些原因导致异常不通过,还有其他方法可以在不堵塞方法返回类型的情况下发出故障信号。替代方法包括返回bool
(考虑方法try_insert
)或使用无效/保留的返回值进行失败,例如string::npos
方法使用的string::find
发生在字符串中。
答案 4 :(得分:0)
exit(0)是一个非常特殊的情况,因为它是一个sentinel值,要求编译器告诉操作系统返回该操作系统上的实际成功值。它完全有可能不是数字0。
正如您所说,许多函数返回0表示成功,但它们主要是“遗留”C库OS接口函数,并且遵循首先开发和部署C的操作系统的接口样式。
在C ++中,0在包装这样的C遗留接口时可能是成功值。您可能考虑使用0表示成功的另一种情况是,当您有效地返回错误代码时,所有错误都是非零值,而0作为非错误值是有意义的。因此,不要将返回值视为布尔值(即使C ++会将其隐式转换为1),但作为错误代码,其中0表示“无错误”。 (实际上,使用枚举通常是最好的。)
但是,您通常应该从某些形式的谓词函数返回布尔值,例如is_empty(),has_dependencies(),can_fit()等,并且通常会在出错时抛出异常。在Alterantive中,根据libc的errno使用子系统(也许是线程)特定的错误代码值,或者接受一个单独的引用/指针参数来加载错误代码。
答案 5 :(得分:0)
int retCode = SaveWork();
if(retCode == 0) {
//Success !
} else if(retCode == ERR_PERMISSIONS) {
//User doesn't have permissions, inform him
//and let him chose another place
} else if(retCode == ERR_NO_SPACE) {
//No space left to save the work. Figure out something.
} else {
//I give up, user is screwd.
}
因此,如果返回0 / false表示失败,则无法区分错误的原因。
对于C ++,您可以使用异常来区分不同的错误。你也可以用
一个全局变量,类似于errno
,您可以在发生故障时进行检查。如果不需要异常或全局变量,则通常使用返回错误代码。
答案 6 :(得分:0)
正如其他答案已经说过的那样,使用0表示成功会使失败的一切都归零。通常(尽管不总是)这意味着使用单个非零值来指示失败的类型。正如已经说过的那样,在那种情况下,你必须将它视为错误代码而不是成功/失败标志。
在这种情况下,我绝对不愿意看到像if(!Method())
这样的声明,这实际上是对成功的考验。对我自己而言,我发现它可能会让人想知道该陈述是否正在测试成功或失败。在我看来,因为它不是一个简单的布尔返回,所以它不应该像一个一样写。
理想情况下,由于返回被用作错误代码,该函数的作者应该提供可用于代替原始数字的枚举(或至少一组定义)。如果是这样,那么我总是希望将测试重写为像if(Method() == METHOD_SUCCESS)
这样的东西。如果作者没有提供,但你有关于错误代码值的文档,那么考虑制作你自己的枚举或定义和使用它。
如果没有别的,我会把它写成if(Method() == 0)
,因为至少它应该仍然清楚读者方法不返回一个简单的布尔值,并且零具有特定的含义。
虽然经常使用该惯例,但它肯定不是唯一的惯例。我已经看到通过使用正值和负值来区分成功和失败的惯例。当一个函数在成功时返回一个计数,但是需要返回一个在失败时不是值计数的东西(通常为-1)时,会发生这种情况。我还看到使用无符号数的变体,其中(unsigned int)-1
(又名0xffffffff)表示错误。还有其他一些我甚至无法想到的事情。
由于没有单一的正确方法,不同时期的不同作者都发明了各种方案。
当然,这完全没有提到异常提供(除其他外)在函数出错时提供信息的完全不同的方式。
答案 7 :(得分:0)
我在我的代码中使用此约定:
int r = Count();
if(r >= 0) {
// Function successful, r contains a useful non-negative value
}
else {
// A negative r represents an error code
}
我倾向于避免bool返回值,因为它们没有任何优点(甚至不考虑它们的大小,它被舍入到一个字节)并限制了函数返回值的可能扩展。
在使用例外之前,请考虑它们带来的性能和内存问题。