C++ 中方法返回的编码约定
我观察到,成功完成方法预期功能的一般编码约定是 0。(如 exit(0))。
这让我很困惑,因为如果我的 if 语句中有方法,并且方法返回 0,则“if 条件”为 false,从而促使我思考一下该方法失败了。当然我知道我必须附加一个“!” (如 if(!Method()) ),但这种约定不是自相矛盾吗?
I have observed that the general coding convention for a successful completion of a method intended functionality is 0. (As in exit(0)).
This kind of confuses me because, if I have method in my if statement and method returns a 0, by the "if condition" is false and thereby urging me to think for a minute that the method had failed. Of course I do know I have to append with a "!" (As in if(!Method()) ), but isn't this convention kind of self contradicting itself ??
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我在代码中使用此约定:
我倾向于避免 bool 返回值,因为它们没有优势(甚至不考虑它们的大小,四舍五入为字节)并且限制了函数返回值的可能扩展。
在使用异常之前,请考虑它们带来的性能和内存问题。
I use this convention in my code:
I tend to avoid bool return values, since they have no advantages (not even regarding their size, which is rounded to a byte) and limits possible extensions of the function's return values.
Before using exceptions, take into account the performance and memory issues they bring.
您需要区分错误代码和错误标志。代码是代表任意数量错误的数字,而标志是指示成功的布尔值。
当谈到错误代码时,我们的想法是:只有一种方法可以成功,但失败的方法有很多种。以 0 作为一个好的单一唯一数字,代表成功,那么你拥有的所有其他数字都是指示失败的一种方式。 (以任何其他方式都没有意义。)
当涉及到错误标志时,这个想法很简单:True 意味着它有效, false 意味着它没有。您通常可以通过其他方式获取错误代码,并采取相应的措施。
有些函数使用错误代码,有些函数使用错误标志。它没有任何令人困惑或倒退的地方,除非你试图将所有东西都视为一面旗帜。并非所有返回值都是标志,这只是您必须习惯的东西。
请记住,在 C++ 中,您通常会处理带有异常的错误。您无需查找错误代码,只需从捕获的异常中获取必要的信息即可。
You need to differentiate between an error code and an error flag. A code is a number representing any number of errors, while a flag is a boolean that indicates success.
When it comes to error codes, the idea is: There is only one way to succeed, but there are many ways to fail. Take 0 as a good single unique number, representing success, then you have every other number is a way of indicating failure. (It doesn't make sense any other way.)
When it comes to error flags, the idea is simple: True means it worked, false means it didn't. You can usually then get the error code by some other means, and act accordingly.
Some functions use error codes, some use error flags. There's nothing confusing or backwards about it, unless you're trying to treat everything as a flag. Not all return values are a flag, that's just something you'll have to get used to.
Keep in mind in C++ you generally handle errors with exceptions. Instead of looking up an error code, you just get the necessary information out of the caught exception.
该约定并不矛盾本身,它与您对该功能的期望使用相矛盾。
其中一个必须改变,而且这不会成为惯例;-)
我通常会写:
或
if (Function() != 0)
,情况则相反。整数可以隐式转换为布尔值,但这并不意味着您总是应该这样做。这里的
0
表示0
,而不是false
。如果你真的愿意,你可以这样写:The convention isn't contradicting itself, it's contradicting your desired use of the function.
One of them has to change, and it's not going to be the convention ;-)
I would usually write either:
or
if (Function() != 0)
with the cases the other way around.Integers can be implicitly converted to boolean, but that doesn't mean you always should.
0
here means0
, it doesn't meanfalse
. If you really want to, you could write:有多种约定,但最常见的 C 函数是在失败时返回 0,在成功时返回正值,因此您可以在
if
语句中使用它(几乎所有 CPU 都有条件跳转,可以测试一个值是否为 0,这就是为什么在 C 语言中“滥用”这个值,0 表示 false,其他所有值都表示 true)。另一个约定是在出错时返回 -1,在成功时返回一些其他值(尤其是在设置 errno 变量的 POSIX 函数中)。这就是 0 可以解释为“成功”的地方。
然后是
退出
。它是不同的,因为返回的值不是由 C 解释,而是由 shell 解释。这里的值0
表示成功,其他每个值表示错误情况(很多工具会告诉您该值发生了什么类型的错误)。这是因为在 shell 中,通常只有 0-127 的范围来返回有意义的值(历史原因,它是一个无符号字节,所有高于 127 的值都意味着被某些信号 IIRC 杀死)。There are various conventions, but most common for C functions is to return 0 on failure and a positive value on success so you can just use it inside an
if
statement (almost all CPUs have conditional jumps which can test whether a value is 0 or not which is why in C this "abused" with 0 meansing false and everything else meaning true).Another convention is to return -1 on error and some other value on success instead (you especially see this with POSIX functions that set the
errno
variable). And this is where 0 can be interpreted as "success".Then there's
exit
. It is different, because the value returned is not to be interpreted by C, but by a shell. And here the value0
means success, and every other value means an error condition (a lot of tools tell you what type of error occurred with this value). This is because in the shell, you normally only have a range of 0-127 for returning meaningful values (historic reasons, it's a unsigned byte and everything above 127 means killed by some signal IIRC).您已将您的问题标记为
[c]
和[c++]
。是哪一个?因为答案会有所不同。你说:
对于 C,这很好。
对于 C++,这绝对不是. C++ 还有另一种机制来表示失败(即异常)。滥用(数字)返回值通常是糟糕设计的标志。
如果由于某些原因而无法使用异常,则可以使用其他方法来发出失败信号,而不会阻塞方法的返回类型。替代方案包括返回
bool
(考虑方法try_insert
)或使用无效/保留的失败返回值,例如string::npos
当在字符串中未找到匹配项时,string::find
方法将使用该方法。You have tagged your question as
[c]
and[c++]
. Which is it? Because the answer will differ somewhat.You said:
For C, this is fine.
For C++, it decidedly is not. C++ has another mechanism to signal failure (namely exceptions). Abusing (numeric) return values for that is usually a sign of bad design.
If exceptions are a no-go for some reasons, there are other ways to signal failure without clogging the method’s return type. Alternatives comprise returning a
bool
(consider a methodtry_insert
) or using an invalid/reserved return value for failure, such asstring::npos
that is used by thestring::find
method when no occurrence is found in the string.exit(0) 是一个非常特殊的情况,因为它是一个哨兵值,要求编译器告诉操作系统返回该操作系统上的实际成功值。它完全有可能不是数字 0。
正如你所说,许多函数成功返回 0,但它们主要是“遗留”C 库操作系统接口函数,并且遵循操作系统的接口风格C首先被开发和部署。
因此,在 C++ 中,当包装此类 C 遗留接口时,0 可能是成功值。您可能会考虑使用 0 来表示成功的另一种情况是,当您实际上返回错误代码时,所有错误都是非零值,并且 0 作为非错误值有意义。因此,不要将返回值视为布尔值(即使 C++ 会将其隐式转换为 1),而应将其视为错误代码,其中 0 表示“无错误”。 (实际上,使用枚举通常是最好的)。
尽管如此,您通常应该从作为某种形式的谓词的函数(例如 is_empty()、has_dependency()、can_fit() 等)返回布尔值,并且通常会在错误时抛出异常。或者,根据 libc 的 errno 使用子系统(可能还有线程)特定的错误代码值,或者接受要与错误代码一起加载的变量的单独引用/指针参数。
exit(0) is a very special case because it's a sentinel value requesting that the compiler tell the operating system to return whatever the real success value is on that OS. It's entirely possible that it won't be the number 0.
As you say, many functions return 0 for success, but they're mainly "legacy" C library OS-interfacing functions, and following the interfacing style of the operating system's on which C was first developed and deployed.
In C++, 0 may therefore be a success value when wrapping such a C legacy interface. Another situation where you might consider using 0 for success is when you are effectively returning an error code, such that all errors are non-zero values and 0 makes sense as a not-an-error value. So, don't think of the return value as a boolean (even though C++ will implicitly convert it to one), but as an error code where 0 means "no error". (In practice, using an enum is typically best).
Still, you should generally return a boolean value from functions that are predicates of some form, such as is_empty(), has_dependencies(), can_fit() etc., and typically throw an exception on error. Alterantively, use a sub-system (and perhaps thread) specific value for error codes as per libc's errno, or accept a separate reference/pointer argument to the variable to be loaded with the error code.
因此,如果返回 0/false 表示失败,则您无法区分错误的原因是什么。
对于 C++,您可以使用异常来区分不同的错误。你也可以使用
一个全局变量,类似于您在发生故障时检查的
errno
。当既不需要异常也不需要全局变量时,通常使用返回错误代码。So, if 0/false were returned to mean failure, you could not distinguish what was the cause of the error.
For C++, you could use exceptions to distinguish between different errors. You could also use
a global variable, akin to
errno
which you inspect in case of a failure. When neither exceptions or global variables are desired, returning an error code is commonly used.正如其他答案已经说过的,使用 0 表示成功,所有内容都非零表示失败。通常(尽管并非总是)这意味着使用各个非零值来指示故障类型。正如已经说过的,在这种情况下,您必须将其视为错误代码而不是成功/失败标志。
在这种情况下,我绝对讨厌看到像
if(!Method())
这样的语句,它实际上是对成功的测试。对于我自己来说,我发现它可能会让人怀疑这个陈述是在测试成功还是失败。在我看来,由于它不是一个简单的布尔返回,因此不应该像这样写。理想情况下,由于返回被用作错误代码,该函数的作者应该提供一个可以用来代替原始数字的枚举(或至少一组定义)。如果是这样,那么我总是更喜欢将测试重写为
if(Method() == METHOD_SUCCESS)
之类的内容。如果作者没有提供该信息,但您有有关错误代码值的文档,请考虑创建自己的枚举或定义并使用它。如果没有别的事,我会把它写成
if(Method() == 0)
因为这样至少读者仍然应该清楚 Method 不会返回一个简单的布尔值,并且零有特定的含义。虽然这一约定经常被使用,但它肯定不是唯一的约定。我见过通过使用积极和消极价值观来区分成功和失败的惯例。当函数返回成功时的计数,但需要返回非失败时的计数值(通常为 -1)时,尤其会发生这种情况。我还看到了使用无符号数字的变体,其中
(unsigned int)-1
(又名 0xffffffff)表示错误。可能还有其他一些我什至无法立即想到的。由于没有单一正确的方法来做到这一点,不同的作者在不同的时间发明了不同的方案。
当然,这一切都没有提到异常(除其他外)提供了一种在函数出现错误时提供信息的完全不同的方式。
As the other answers have already said, using 0 for success leaves everything non-zero for failure. Often (though not always) this means that individual non-zero values are used to indicate the type of failure. So as has already been said, in that situation you have to think of it as an error code instead of an success/failure flag.
And in that kind of situation, I absolutely loathe seeing a statement like
if(!Method())
which is actually a test for success. For myself too, I've found it can cause a moment of wondering whether that statement is testing for success or failure. In my opinion, since it's not a simple boolean return, it shouldn't be written like one.Ideally, since the return is being used as an error code the author of that function should have provided an enum (or at least a set of defines) that can be used in place of the raw numbers. If so, then I would always prefer the test rewritten as something like
if(Method() == METHOD_SUCCESS)
. If the author didn't provide that but you have documentation on the error code values, then consider making your own enum or defines and using that.If nothing else, I would write it as
if(Method() == 0)
because then at least it should still be clear to the reader that Method doesn't return a simple boolean and that zero has a specific meaning.While that convention is often used, it certainly isn't the only one. I've seen conventions that distinguish success and failure by using positive and negative values. This particularly happens when a function returns a count upon success, but needs to returns something that isn't a value count upon failure (often -1). I've also seen variations using unsigned numbers where
(unsigned int)-1
(aka 0xffffffff) represented an error. And there are probably others that I can't even think of offhand.Since there's no single right way to do it, various authors at various times have invented various schemes.
And of course this is all without mentioning that exceptions offer (among other things) a totally different way to provide information when a function has an error.