Matt Joiner
Matt Joiner

Reputation: 118480

Standard C functions: Check for -1 or 0?

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.

Upvotes: 5

Views: 1579

Answers (9)

Secure
Secure

Reputation: 4378

Whatever you do, never ever shortcut a test for success with

if (!ret) 

It's confusing and someone (including yourself) will misread it later as a test for failure. It's generally better to use explicit tests.

Upvotes: 2

John Kugelman
John Kugelman

Reputation: 361585

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:

if (ret == -1) {
    perror(...);
}

// or

if (ret < 0) {
    perror(...);
}

(I prefer the first one but the second more general one doesn't bother me.)

Upvotes: 8

Ben Voigt
Ben Voigt

Reputation: 283614

For most POSIX API functions, negative values are errors. So I'd test for failure with if (ret < 0).

Upvotes: 1

MAK
MAK

Reputation: 26586

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.

Upvotes: 0

ssube
ssube

Reputation: 48247

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.

Upvotes: 3

mouviciel
mouviciel

Reputation: 67831

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.

Upvotes: 2

Chubsdad
Chubsdad

Reputation: 25497

Cert guidelines seem to prefer the '!= 0' check as is valid in many of their example code snippets.

Upvotes: 2

Mark Elliot
Mark Elliot

Reputation: 77034

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)

Upvotes: 1

dja
dja

Reputation: 1503

Comparing the man pages for truncate and fflush, both return 0 on success, but return different values for error (truncate -> -1, fflush -> EOF). So I'd check for 0.

Upvotes: 3

Related Questions