标准 C 函数:检查 -1 还是 0?
许多标准 C 和 POSIX 函数在错误时返回 -1
,在成功时返回 0
,例如 截断
, fflush
, msync
等。
int ret = truncate("/some/file", 42);
使用 ret != -1
检查是否成功是否是更好的做法或 ret == 0
,为什么?
我的想法
根据我的经验,大多数人都会检查错误情况 (ret != -1
),因为通常只有一个(考虑返回 NULL
或 的函数) EOF 错误)。然而事后看来,人们可以看到这些函数可以从直接返回 errno 中受益(其中 0 被认为没有错误)。
还需要担心函数返回 0
或 -1
以外的内容,或者稍后添加其他返回值。在这些场景中,测试指示成功的“最严格”值范围 (ret == 0
) 是有意义的。
Update0
我的一个假设是人们知道 EOF
通常定义为 -1
。
Many standard C and POSIX functions return -1
for error, and 0
on success, for example truncate
, fflush
, msync
, etc.
int ret = truncate("/some/file", 42);
Is it better practice to check for success with ret != -1
or ret == 0
, and why?
My Thoughts
It's my experience most people check for the error case (ret != -1
), as there is typically only one (consider functions that return NULL
or EOF
on error). However in hindsight, one could see these functions could benefit from returning errno
directly (where 0
is considered no error).
There is also the worry that a function returns something other than 0
or -1
, or that additional return values are later added. In these scenarios, it makes sense to test for the "tightest" range of values indicating success (ret == 0
).
Update0
It's an assumption of mine that people are aware that EOF
is typically defined as -1
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这取决于该函数是 C 标准库函数还是 POSIX 函数。 C 函数没有统一的返回码标准,因此我会根据具体情况使用最有意义的测试。
另一方面,POSIX 更加一致。几乎所有 POSIX 函数都定义为返回 -1,并在
errno
中提供更具体的错误代码。有些函数仅返回 0 表示成功,而其他函数则有多个成功值。例如,open() 返回文件描述符,read() 返回读取的字节数等。为了保持一致性,我喜欢在调用 POSIX 函数时始终使用相同的测试:不要测试成功,要测试失败。今天,在出错时返回 -1 的 POSIX 函数将始终准确地返回 -1,因此我会对所有这些函数使用两个检查之一:(
我更喜欢第一个,但第二个更通用的检查不会打扰我。)
It depends on whether the function is a C standard library function or a POSIX function. C functions don't have a uniform standard for return codes so I'd use whatever test makes the most sense on a case-by-case basis.
POSIX, on the other hand, is more consistent. Almost all POSIX functions are defined to return -1 with a more specific error code available in
errno
. Some functions simply return 0 for success, while others have a multitude of success values. For example,open()
returns file descriptors,read()
returns the number of bytes read, etc.For consistency I like to always use the same test when invoking POSIX functions: don't test for success, test for failure. POSIX functions that today return -1 upon error will always return exactly -1, so I would use one of two checks for all of them:
(I prefer the first one but the second more general one doesn't bother me.)
在我看来,这实际上取决于您需要做什么以及返回值的范围。
接听具有一个成功值和多个失败值的呼叫。通常,针对成功返回值进行
==
或!=
比检查任何失败值更容易。在这种情况下,如果您需要记录并在失败时返回或抛出,您将针对!= success
进行测试。在一和一的通话中,所需的行为更为重要,因此我建议选择更具可读性的。如果您的代码需要对失败做出反应并可能返回,请检查
== failure
而不是!= success
。前者更具可读性,因为它需要一步思考,并且命名失败常数可能会有所帮助。您可能还需要考虑哪个更有可能并首先处理,或者哪个在数值上更大或更小。
在您的情况下,两个函数共享一个成功代码并且具有不同的失败代码,它会落在看起来更可读的一个上。我同意在这两种情况下测试
== 0
看起来会更好,但这实际上取决于调用之间有多少代码。如果您有几十行,则可读性可能不会有太大差异。如果非常接近,您甚至可以将结果进行“或”运算,从而节省更多步骤。In my opinion, it really depends on what you need to do and the range of return values.
Take a call with one success value and many failure values. It's generally easier to
==
or!=
against the successful return value than check against any failure values. In this case, you would test against!= success
if you need to, say, log and return or throw in case of a failure.In a call with one and one, the desired behavior is more important, so I suggest choosing the more readable. If your codes needs to react to and possibly return on failure, then check for
== failure
instead of!= success
. The former is more readable, since it takes one step of thinking and the failure constant may be helpfully named.You may also want to consider which is more likely and handle that first, or which is numerically greater or lesser.
In your case, with two functions sharing a success code and with differing failure codes, it falls to whichever seems more readable. I would agree that testing for
== 0
in both cases would seem better, but it really depends on how much code comes between the calls. If you have a few dozen lines, there might not be much of a difference in readability. If it's very close, you might even be able to OR the results together and save yourself a few more steps.比较
truncate
和fflush
的手册页,成功时都返回 0,但错误时返回不同的值(truncate -> -1、fflush -> EOF)。所以我会检查 0。Comparing the man pages for
truncate
andfflush
, both return 0 on success, but return different values for error (truncate -> -1, fflush -> EOF). So I'd check for 0.证书指南 似乎更喜欢“!= 0”检查,因为在许多示例代码片段中都是有效的。
Cert guidelines seem to prefer the '!= 0' check as is valid in many of their example code snippets.
请务必检查手册页中的返回代码。
通常 0 表示成功,但也存在例外,例如
printf()
。检查
man 2 intro
中的 errnos 和系统调用的错误代码。Always check the man pages for return codes.
Usually 0 means success, but exceptions exist such as
printf()
.Check
man 2 intro
for errnos and error codes of system calls.无论您做什么,都永远不要捷径成功测试。
这会令人困惑,并且有人(包括您自己)稍后会误将其视为失败测试。通常最好使用显式测试。
Whatever you do, never ever shortcut a test for success with
It's confusing and someone (including yourself) will misread it later as a test for failure. It's generally better to use explicit tests.
如果定义是 0 表示成功,并且您想要检查成功,那么您应该检查是否等于 0。(这除了剪切可读性之外没有其他原因)
If the definition is that 0 means success, and you want to check for success then you should check equivalence to 0. (and this is for no other reason than shear readability)
对于大多数 POSIX API 函数,负值都是错误。因此,我会使用
if (ret < 0)
来测试失败。For most POSIX API functions, negative values are errors. So I'd test for failure with
if (ret < 0)
.我的经验法则是,此类函数通过返回值返回错误代码(或仅返回是否发生错误)。因此,对我来说,返回值 0 意味着没有任何此类内容可返回,并且没有发生错误,这是有道理的。因此,如果我想测试函数是否成功,我只需检查返回值是否为0,如果不是,则检查错误值是什么并进行相应处理。
My rule of thumb is that functions like these return the error code (or just whether an error occurred) through the return value. So, for me it makes sense that a return value of 0 means that there was nothing of that sort to return and that no error occurred. Therefore I just check if the return value was 0 if I want to test whether the function was successful, and if not just check what the error value was and deal with it accordingly.