tags:

views:

699

answers:

8

Hi, I know EXIT_SUCCESS/EXIT_FAILURE is typically used for main() exit to indicate the successfulness of a program.

But is it also used (commonly or suggested) for normal function returns? I'm trying to write some "standard" code so wondering if I should use them instead of 0 or -1..

Thanks.

A: 

I'd say it doesn't matter.

Michael Krelin - hacker
I knew the downvote is coming. Apparently, it does matter to some ;-)
Michael Krelin - hacker
See Jerry's answer
Ivan Nevostruev
It is of doubtful nature, but even that doesn't deserve downvote, I believe.
Michael Krelin - hacker
Upvoted because what *does* matter is knowing what the function you're calling returns and how to handle that value correctly. Library functions don't follow any consistent set of rules, so inventing rules will always run foul of a few of them.
Dan Olson
very true. One of the answers here almost sensibly suggests using the same convention like libraries, but it is hard to stick with libraries that use the same convention, so knowing what you're doing is important. Actually, it would be important even if libraries were consistent ;-)
Michael Krelin - hacker
+1  A: 

If you're using error codes, using the same constants for success that your libraries use makes things clearer.

Anon.
A: 

They're generally a poor idea for normal function returns. EXIT_SUCCESS is typically 0, and EXIT_FAILURE is typically 1. If somebody accidentally treats these as boolean values, they'll have exactly the opposite meaning of what you'd normally use -- i.e., EXIT_SUCCESS will be interpreted as false, which normally signals failure, while EXIT_FAILURE will be interpreted as true, which normally signals success.

Since it seems to be controversial, consider at least a few C library functions that return 0/false to indicate failure:

malloc
calloc
fopen
fread
fwrite
fgets
printf
fprintf
getenv
bsearch

It's certainly true that in some of these cases the "0" is a NULL pointer -- but it's also true that quite a number of these (fopen, malloc, etc.) are things essentially every C programmer uses on a regular basis, and if he's even trying to do his job decently at all, he checks the return values -- and in that check, if(x()) means the function has succeeded.

Jerry Coffin
Opposite to what? The vast majority of c library functions returns zero for success. And almost never zero for failure (negative, instead).
Michael Krelin - hacker
but there's no boolean type in C, right?
Figo
@Figo:Boolean *type* is irrelevant -- an integer value can be interpreted as a Boolean. For what it's worth, C99 does add a Boolean type though. Interpretation of 0 as "false" and non-zero as "true" has been part of C since its beginning.
Jerry Coffin
Jerry, `if(x())` would *not* normally mean "if x succeeded" for a c programmer.
Michael Krelin - hacker
Those of your list that do not return null-pointer, return *counter*. And zero value does *not* indicate failure. `printf` family functions in particular return negative value to indicate failure.
Michael Krelin - hacker
@Figo there is a boolean type in C99.
asveikau
+2  A: 

Many of the functions defined by the POSIX standard return 0 for success or a non-zero error code to indicate failure.

A lot of POSIX functions are defined to return 0 for success, -1 for failure and set errno global variable to indicate what failed. But a global errno doesn't work well in a multi-threaded program.

progrmr
afaik most (common) implementations of `errno` are thread-safe - the C standard explicitly allows `errno` to be implemented as a macro to make this possible
Christoph
in addition to what Christoph says, many compiler/OS combinations will allow you to annotate variables as existing in thread-local storage. so a global isn't always a problem even without a macro.
asveikau
+3  A: 

You should never use EXIT_SUCCESS or EXIT_FAILURE outside of the context of a call to exit() or the return value to main(). The values of these integers are not specified by the standard, so you cannot write portable code if you assume that they are 0 or 1 respectively.

The standard does specify that exit(0) and a return 0 from main() behave the same way as exit(EXIT_SUCCESS) and return EXIT_SUCCESS, but these values are "special" in that they are to be interpreted in an implementation defined manner. That is, the actual value passed to the system may not be 0, and the constant value of EXIT_SUCCESS is free to not be 0 if the implementation desires, so long as return 0 from main and return EXIT_SUCCESS from main behave the same way.

If you use these values in your functions, your callers will have to compare against EXIT_SUCCESS directly to determine if the function succeeded, which personally speaking I would find very inconvenient.

int MyFunction1 () { /* ... */ return EXIT_SUCCESS; }
int MyFunction2 () { /* ... */ return 0; }

// Portable:
if (MyFunction1 () == EXIT_SUCCESS) { ... }
if (MyFunction2 () == 0) { ... }
if (!MyFunction2 ()) { ... }

// Not portable:
if (MyFunction1 () == 0) { ... }
if (!MyFunction1 ()) { ... }
if (MyFunction2 () == EXIT_SUCCESS) { ... }

The problem becomes more obvious with EXIT_FAILURE:

int MyFunction1 () { /*... */ return EXIT_FAILURE; }
// Not portable
if (MyFunction1 ()) { ... }
if (MyFunction1 () == 1) { ... }
// The only way to make this portable.
if (MyFunction1 () == EXIT_FAILURE) { ... }
Dan Olson
@Dan your comment seems contradictory to me: you suggest never use EXIT macro outside context of exit or main, and then show the code where EXIT macro one is more portable.
Figo
Thanks for the comment, I'll clarify.
Dan Olson
A: 

I don't use the EXIT_* macros for functions because:

  • Some of my functions need to return a signed errno on failure
  • Some of my functions need to return the # of bytes read or written
  • I prefer to handle errors with a typed callback function pointer
  • I like to remain consistent

Now, we come to main():

  • POSIX Says you can exit with a value of 0 - 255. Its very, very useful to return a meaningful exit status rather than just success or failure. This helps make scripts more intelligent. In this regard, only EXIT_SUCCESS is useful.
Tim Post
A: 

EXIT_SUCCESS is a simbolic constant.-

You can use EXIT_SUCCESS and EXIT_FAILURE as well as 0 for OK and non 0 for failure.

Depends on taste, you can also make this

#define WRONG 1
#define COOL  0

and return those.-

Use whatever you feel more comfortable with, but keep your selection all the way.

Hope this helps!

MRFerocius
I'd recommend that you remove semicolons from your defines ;-)
Michael Krelin - hacker
You are right hacker, thanks for pointing it out.-
MRFerocius
+3  A: 

Do no use EXIT_SUCCESS or EXIT_FAILURE for functions, or for anything other than exit calls for that matter.

Feel free, however, to define your own types for your functions to return, but that depends on the situation and the exact code you're writing.

Some common approaches are:

  • Functions returning pointers almost always return NULL (which is 0 according to ANSI C, but NULL is a more descriptive name to use) in case of errors
  • Functions that return indexes or positions usually return -1 on error (because it can't be a real index, while 0 can, so 0 isn't a good error return value)
  • In more complex cases, you may find it useful to define a new return type with an enum, one of which is your error, and check for that.

As long as you are consistent, don't stray away from the conventions too far, and document everything, you should be OK.

Eli Bendersky
+1 for providing well-explained alternatives
Platinum Azure