Figo
Figo

Reputation: 1720

What are common approaches to meaningful function return values?

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..

Upvotes: 6

Views: 4383

Answers (7)

MRFerocius
MRFerocius

Reputation: 5629

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!

Upvotes: 0

Eli Bendersky
Eli Bendersky

Reputation: 273406

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.

Upvotes: 13

Dan Olson
Dan Olson

Reputation: 23367

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) { ... }

Upvotes: 4

user50049
user50049

Reputation:

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.

Upvotes: 0

progrmr
progrmr

Reputation: 77193

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.

Upvotes: 3

Anon.
Anon.

Reputation: 59973

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

Upvotes: 1

Michael Krelin - hacker
Michael Krelin - hacker

Reputation: 143071

I'd say it doesn't matter.

Upvotes: 0

Related Questions