A while back I switched the way I handled c style errors.
I found a lot of my code looked like this:
int errorCode = 0;
errorCode = doSomething();
if (errorCode == 0)
{
errorCode = doSomethingElse();
}
...
if (errorCode == 0)
{
errorCode = doSomethingElseNew();
}
But recently I've been writing it like this:
int errorCode = 0;
do
{
if (doSomething() != 0) break;
if (doSomethingElse() != 0) break;
...
if (doSomethingElseNew() != 0) break;
} while(false);
I've seen a lot of code where nothing gets executed after there's an error, but it has always been written in the first style. Is there anyone else who uses this style, and if you don't, why?
Edit: just to clarify, usually this construct uses errno
otherwise I will assign the value to an int
before breaking. Also there's usually more code than just a single function call within the if (error == 0 )
clauses. Lots of good points to think on, though.
The classic C idiom is:
Note that C returns the assigned value from an assignment, enabling a test to be performed. Often people will write:
but I retained the
== 0
for clarity.Regarding your idioms...
Your first idiom is ok. Your second idiom is an abuse of the language and you should avoid it.
I've seen this pattern before and didn't like it. Usually, it could be cleaned up by pulling the logic into a separate function.
The code then becomes
Combining this with cleanup becomes pretty easy too, you just use a goto and error handler like in eclipses answer.
This should be done through exceptions, at least if the C++ tag is correct. There is nothing wrong if you are using C only, although I suggest to use a Boolean instead as you are not using the returned error code. You don't have to type != 0 either then...
How about this version then
I'd usually just do something like your first example or possibly with a boolean like this:
But if you are really keen on the terseness of your second technique then you could consider this approach:
Just don't expect the maintenance programmers to thank you!
There seems to be a deeper problem here than your control constructs. Why do you have such complex error control? I.e. you seem to have multiple ways of handling different errors.
Typically, when I get an error, I simply break off the operation, present an error message to the user, and return control to the event loop, if an interactive application. For batch, log the error, and either continue processing on the next data item or abort the processing.
This kind of control flow is easily handled with exceptions.
If you have to handle error numbers, then you can effectively simulate exceptions by continuing normal error processing in case of an error, or returning the first error. Your continued processing after an error occurs seems to be very fragile, or your error conditions are really control conditions not error conditions.
The second style is commonly used for managing resource allocations and de-allocations in C, where RAII doesn't come to the rescue. Typically, you would declare some resources before the do, allocate and use them inside the pseudo-loop, and de-allocate them outside.
An example of the general paradigm is as follows:
Having said that, RAII solves the same problem with much cleaner syntax (basically, you can forget the cleanup code altogether) and handles some scenarios that this approach does not, such as exceptions.