简体   繁体   中英

how to deal with error return in c

How does one deal with error return of a routine in C, when function calls go deep?

Since C does not provide an exception throw mechanism, we have to check return values for each function. For example, the "a" routine may be called by "b", and "b" may called by many other routines, so if "a" returns an error, we then have to check it in "b" and all other routines calling "b".

It can make the code complicated if "a" is a very basic routine. Is there any solution for such problem? Actually, here I want to get a quick return path if such kind error happens, so we only need to deal with this error in one place.

You can use setjmp() and longjmp() to simulate exceptions in C.

http://en.wikipedia.org/wiki/Setjmp.h

There are several strategies, but the one I find the most useful is that every function returns zero on success and nonzero for an error, where the specific value indicates the specific error.

This combined with early return logic actually makes the functions quite easy to read:

int
func (int param)
{
    int rc;
    rc = func2 (param);
    if (rc)
        return rc;

    rc = func3 (param);
    if (rc)
        return rc;

    // do something else
    return 0;
}

I'm afraid that's the way it is. Without exceptions, you have to check the return value of every function in the call chain.

In the general case, no. You'll want to make sure your function calls worked as expected. Return codes are your main mechanism for ensuring this (although setting a global error number or error flag may also be appropriate, depending on context - not that it simplifies things much).

Adopting one of the techniques others have suggested should allow you to make your error checking uniform and easier to read. This will go a long way towards keeping things maintainable.

For some basic functions though, the odds of failure may be low enough not to bother, eg.

int sum(int a, int b) {
  return a + b;
}

really doesn't need to be checked. But that system call to create a new window really should be.

You make a list of error_codes (I use enum for that) and use them "flat" in all your app. So if b calls a, and get one of the error codes, you can decide if you go on, or return back the original error code.

The user/programmer should have a list of all error codes...

The best way is to design functions, whenever possible, in ways that cannot fail. This is impossible if they do I/O or memory allocation or other things with side effects, so avoid those. For example, instead of having a function that allocates memory and copies a string, have a function that gets pre-allocated memory to which it copies a string. Or you might have only one place where I/O happens, the rest of the program just manipulates data in memory.

Alternatively, you may decide that certain kinds of errors warrant killing the process. For example, if you're out of memory, it is hard to recover from that, so you might as well crash. (But do that in a way that is user-friendly: checkpoint relevant data to disk continuously so the user may recover.) This way, functions can pretend they never fail.

The setjmp suggestion Murali VP is also worth checking out.

AFAIK C is a structural programming language.

If this is the problem, the same would apply to RTL functions like fopen, fscanf etc ...

So I guess it is better to propagate errors.

You could use a macro.

#define FAIL_FUNC( funcname, ... )    if ( !funcname( _VA_ARGS_ )  ) \
                                           return false;

This way you maintain the same system but without having to write the same code each time ...

You can use an ugly if pyramid like:

if (getting resource 1 succeeds) {
    if (getting resource 2 succeeds) {
        if (getting resource 3 succeeds) {
            do something;
            return success;
        }
        free resource 2;
    }
    free resource 1;
}
return failure;

or the equivalent with goto (which looks much nicer):

if (getting resource 1 failed) goto err1;
if (getting resource 2 failed) goto err2;
if (getting resource 3 failed) goto err3;
do something;
return success;

err3:
free resource 2;
err2:
free resource 1;
err1:
return failure;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM