C or C++ Return Status
Solution 1
We use this in C where I work:
int err = foo();
if (err) {
// armageddon
}
The assignment and if could be combined, but with more complicated function calls it gets more confusing and some people are confused by assignment in a conditional (and gcc hates it).
For C++, I would prefer exceptions if available, otherwise the above.
Edit: I would recommend returning 0 on success and anything else on error. This is what unix command line utilities do.
Solution 2
If you really want to use status codes that way, use them with an enum
or block of #define
statements that describe the intention of the status code.
For example:
enum
{
kSuccess = 0,
kFailure = -1,
}
function foo()
{
return kSuccess;
}
if (kSuccess == foo())
{
// Handle successful call to foo
}
else
{
// Handle failed call to foo
}
This way, the intention is clear and there's no error-prone guesswork when someone wants to use or maintain your code in the future.
Solution 3
if (foo()) {
// what to do if false
} else {
// what to do if true
}
The problem with this approach is excess nesting. Suppose you have three functions you want to call:
if(foo1()) {
if(foo2()) {
if(foo3()) {
// the rest of your code
} else {
// handle error
}
} else {
// handle error
}
} else {
// handle error
}
To solve the excess nesting problem, invert the return value:
if(!foo1()) {
// handle error
return;
}
if(!foo2()) {
// handle error
return;
}
if(!foo3()) {
// handle error
return;
}
This solution suffers from another problem. It mixes the program logic with the error handling code. This complicates everything. Ideally, you want the program logic and error handling separated. This problem can be fixed with the goto
if(!foo1())
goto error1;
if(!foo2())
goto error2;
if(!foo3())
goto error3;
return;
error1:
// handle error
return;
error2:
// handle error
return;
error3:
// handle error
return;
Much cleaner.
Also, the goto can solve the problem of resource deallocation. See Using goto for error handling in C by Eli Bendersky for more details.
Solution 4
Best practice is to document your code so that yourself and others can quickly look up what the return codes will be when doing error checking.
Solution 5
The return statuses should be defined in your interface and known to the caller. Some return 0 on failure (because it's easy to check with !
), some return 0 on success (because they have enum
of error codes, with OK
being the first item).
There's no law or standard, each interface defines its own conventions. In C++ - use exceptions.
Jason Marcell
I work at Apple in Safari and WebKit Operations, providing support for continuous integration, testing, deployment and other infrastructure and tooling needed to keep "The Internet" humming along quietly on your iPhone and Mac.
Updated on June 16, 2022Comments
-
Jason Marcell almost 2 years
What are the best practices for writing C or C++ functions that return an int that represents a status code?
Specifically, I want to know about the client usage but other tips are welcome.
For example, can I write something like this:
int foo() { return 0; // because everything was cool }
And then use it like this?
if (foo()) { // what to do if false, e.g. non-zero, e.g. not OK } else { // what to do if true, e.g. zero, e.g. OK }
This should work because best practices typically dictate that a status code of
0
means everything was OK and also0
meansfalse
in a boolean statement.However, this wouldn't be good, right:
if (!foo()) { // what to do if true } else { // what to do if false }
-
Andy Finkenstadt over 12 years// And armageddon sick of it, too. :-)
-
dario_ramos over 12 yearsSwallowing exceptions is bad practice, for lots of reasons: google.com.ar/…
-
Jason Marcell over 12 yearsWait, but "not"-ing something non-zero does not necessarily make it zero, right?
-
Jay over 12 years"the result is 1 if the operand is 0, and the result is 0 if the operand is not 0." c.comsci.us/etymology/operator/logicalnot.html
-
R.. GitHub STOP HELPING ICE over 12 yearsI would add that the reason it's usually best to return 0 on success and nonzero on error (as opposed to boolean 1/0 meaning true/false) is that there are usually many reasons an operation can fail but only one type of success.
-
Jason Marcell over 12 yearsYes, but since there is no first-class Boolean type in C, isn't the ! just an arithmetic negation on the integer operand? It's not a logical negation, right? It just flips the bits.
-
Jay over 12 yearsso "not"-ins something non-zero does necessarily make it zero
-
Jay over 12 years!10 is equal to 0, the article explains this
-
Jay over 12 yearsbtw, if you want actual boolean literals, there are a few options. See stackoverflow.com/questions/1921539/using-boolean-values-in-c
-
adpalumbo over 12 yearsIt's just a style thing, used to help constant values stand out from variables and other identifiers.
-
Jay over 12 yearsYou're confusing the not operator "!" with the bitwise not operator "~". They are two separate things. The "~" operator has the effect you're thinking of.
-
GManNickG over 12 years@adpalumbo: But why do they need to stand out? :)
-
R.. GitHub STOP HELPING ICE over 12 yearsIs it akin to Hungarian notation? Or is "k" an initial for your library/project/company? Or..?
-
adpalumbo over 12 yearsIt appears in a lot of places: it's used in Hungarian notation, Apple's naming convention (which is not Hungarian), and many others. The real reason it appears in this sample is simply because it's used in my current employer's style guide, so its second nature for me now.
-
Oscar Korz over 12 yearsIn and of itself, that doesn't matter. The significance of 0 is that programmers are lazy and this allows the terse
if(foo())
to work. Success could just as easily be 42, and we could all writeif (foo() != 42)
-
GManNickG over 12 years@Jason: C has a boolean type, in
stdbool.h
. -
Alexander Oh over 12 years@Jay: you should not do this with the resource deallocation. The crucial point is to have a single return for multiple error cases. imagine you have three resources allocated - one after every if you want to deallocate them in reverse order you would have three labels. then you would jump to the case where you deallocate all resources if you fail in the last if. and if you have to abort earlier you'd just deallocate 2 resources and jump to the penultimate label a.s.o. if you always want to deallocate all resources just skip the return in the middle.
-
Jason Marcell over 12 years@GMan, thanks for pointing out
stdbool.h
. I had never heard of that before. However, I'll still point out that it just uses macros and also that this is part of a library and not the core language, so I might still argue that C does not have a boolean type. Granted, it is a "standard" library, so I guess you can count on it being there. So that's just about as good as it being part of the core language, right? -
GManNickG over 12 years@Jason: Sure. This statement is true: C has a boolean type. How you use that type is not a concern, but you are guaranteed that it's there in a well-defined manner. 'Core' or 'library', I think, is only a categorization within the language; note, then, that to even ask if it's part of the core or of the library, we already have to agree it's, at least, part of the language itself.