Originally published by Robert Beisert at fortcollinsprogram.robert-beisert.com

Unconventional Uses – if-else chains

Stop me if you’ve heard this one. You’ve just put together a program, and the logic looks alright, so you start handling error cases. As you go, you drop in dozens of new variables, lay down return values every other line, and throw down hundreds of print statements. Worse still, you might resort to “assert()” functions.

Or maybe you’re an OOP’er, and you throw everything into try-catch blocks, complete with exception handling functions.

Either way, the result is usually slow, buggy, and ultimately unreadable. As a result, maintenance becomes a nightmare.

Say Hello to If-Else chains

Did you know that you can execute functions within condition statements?

Moreover, did you know that you can splice tests onto functions using the mighty comma (at least in C)?

These revelations lead us to the long if-else chain, in which we’re always testing for the error in the simplest way possible.

For example:

[code language=”c”] int main(int argc, char *argv[])
{
    int i;
    char *panda;

    if(panda = malloc(i), panda == NULL)
    {
        printf("oopsn");
    }
    else if(argc != 2)
    {
        printf("oopsn");
    }
    else if(strncpy(panda, argv[1], i) == NULL)
    {
        printf("oopsn");
    }
    else if(printf("%sn", panda), 0)
    {
        printf("Theoretically no way to get this error messagen");
    }
    else
        return 0;

    FREE(panda);
    return -1;
}
[/code]

Let’s look at each test individually.

[code language=”c”]if(panda = malloc(i), panda == NULL)[/code]

This is a standard test, albeit written in a fairly clumsy manner. In this line, we allocate i bytes to the string <panda>, THEN test to see whether the pointer we allocated to panda is NULL. If it is, we print the error message and drop down to the end of the program.

[code language=”c”]else if(argc != 2)[/code]

Recall, if you will, that argc is always at least equal to 1, as it counts the program name as well as any arguments. This test ensures that we get exactly one argument, which we will later use as a string.

[code language=”c”]else if(strncpy(panda, argv[1], i) == NULL)[/code]

strncpy is a regulated string copy function which stores the value of the second argument (argv[1]) back in the first argument (panda). I say regulated because it will only copy the third argument (i) number of bytes.

Importantly, strncpy returns the pointer to panda. If that pointer is NULL, it means that the strncpy failed, and we need to return an error message.

And don’t say it can’t happen, because that’s just loony talk. Always test everything you can, so long as the test is basically free.

[code language=”c”]else if(printf("%sn", panda), 0)[/code]

This line is a simple printf statement, but we don’t want to break the chain. That’s why we comma splice the 0.

When we use the comma splice, only the LAST element is evaluated. Therefore, even though we can’t evaluate the printf statement, we can keep the chain going (because if 0 always evaluates FALSE).

[code language=”c”]else return 0[/code]

This is our success case. If we get this far, we’ve won.

Everything after the final else happens when we fall off the chain. This is our overall error-catching code. In this case, we FREE panda (should be handled above, as we can’t free NULL, but it’s here for demonstration purposes), and return -1, indicating that the execution failed at some point.