Search code examples
cerror-handlingshort-circuiting

Short circuit error handling in C


I was wondering if there was a better way of handling the case in C where you want to exit a function as soon as you encounter an error in a series of expressions. (in this case, its a function that returns a NULL on error)

e.g. in some C code where they tried to short circuit error handling by combining a series of statements with AND (&&).

return doSomething() && 
     doSomething2() && 
     doSomething3() && ... ;

This irritates me since we're cramming so much on one line in one statement. But I guess the alternative is

if (!(value = doSomething()))
    return NULL;
if (!(value = doSomething2()))
    return NULL;
etc
return value;

But what about short circuit error evaluation that I've seen in perl and bash scripts..

int die(int retvalue) {
    exit(retvalue);
}
.....
(value = doSomething()) || die(1);
(value = doSomething2()) || die(2);
(value = doSomething3()) || die(3);
return value;

The main problem with this is that the RHS has to be an expression so you can't really goto or return from the function. Would anyone find this of value or is it too limited?

edit: I guess I should have meant to include newlines in the first example. The problem is that you need to be careful if you decide to add another expression in the middle.


Solution

  • I've seen the use of GOTOs in C for this exact purpose.

    Because there isn't a 'finally' construct in C, a method was needed to free all your memory even if you were exiting a function early.

    So it's essentially as follows (could someone correct my C syntax if I'm wrong, I'm a bit rusty)

    int foo()
    {
        /* Do Stuff */
        if(!DoSomething())
            GOTO Failure;
    
        if(!DoSomething2())
            GOTO Failure;
    
        if(!DoSomething3())
            GOTO Failure;
    
        /* return success */
        return true; 
    
        Failure:
        /* release allocated resources */
        /* print to log if necessary */
        return false;
    }
    

    Important note Do not use GOTOs for execution flow. They should only be used on error, and only to go to the end of the current function. If you use them for anything else, you're creating spaghetti code that could possibly destroy the fabric of reality. Just don't do it.

    EDIT

    As one of the posters noted, using Exit(x) will kill your entire program, which keeps that solution reserved for fatal errors. However your original proposed solution (DS() && DS2() && DS3()) all on one line poses a problem for error handling.

    If you wanted to wrap the functions in some sort of function specific error handling, there is no way to do it when you wrap the function calls all in one line. So, at the very least you could do something like

    int result1 = 0;
    int result2 = 0;
    int result3 = 0;
    
    result1 = DoSomething();
    
    if(result1)
        result2 = DoSomething2();
    
    if(result2)
        result3 = DoSomething3();
    
    return result1 && result2 && result3;
    

    Because this method would not preclude error handling.