Styles of dealing with errors in C? [duplicate]
Possible Duplicate:
Error handling in C code
Hello people. I'm using C for some small projects and I see how, because it doesn't have dedicated error handling constructs, I have to pollute my algorithm with extra conditional blocks. My question is how do you prefer to deal with errors, and justification why. I'm torn between two ways... if you have a third one, post it. Thanks.
///////////////////////////////////////////
// method 1
// stuff t开发者_如何学Pythonhat can go wrong;
if (test1 == failed)
{
// print error;
// exit;
}
else
{
// more stuff that can go wrong;
if (test2 == failed)
{
// print error;
// exit;
}
else
{
// ... and so on...
}
}
///////////////////////////////////////////
// method 2
// stuff that can go wrong;
if (test1 == failed)
{
// print error;
// exit;
}
// more stuff that can go wrong;
if (test2 == failed)
{
// print error;
// exit;
}
// ... and so on...
Some people won't agree with me on this, but I use goto's. Inside each function, at the end I have a block at the end which looks like this
if (0)
{
ERROR:
// Handle errors, and exit/return after potentially freeing resources
}
Then I use if (something_bad) goto ERROR;
without elses or other stuff.
Many people don't like goto's, but this is the way to do this instead of duplicating code. If you really insist on not using goto's I'd do this:
#define LOCAL_ASSERT(COND) if (COND) { \
/* Handle errors, and exit/return after potentially freeing resources */ \
}
Add a define for it at the begining of each function, and then add add a #undef LOCAL_ASSERT
at the end of the function. This allows for different error handling at each function, without polluting the entire program with different macro names.
Then I simply use LOCAL_ASSERT(cond)
everywhere.
Edit: to make myself clearer, this is to save writing the error handling code many times. If you want small customizations, it's easy to set an error variable string (or add it as a macro parameter). I simply don't like the if else things. I usually do
// method 1
if (error) goto ERROR; // no else
// method 2
LOCAL_ASSERT(cond);
Elses do pollute your code and require more indentation which is sometimes annoying.
I know it's user preference somewhat, but I try really hard to establish a single exit point from each function, or at most, two exit points (but they must be obvious and easy to breakpoint):
const Bool funcFoo(int someval, int someval2, int someval3)
{
if(someval == okval)
{ // We're ok
if(someval2 == okval2)
{ // Still ok.
if(someval3 == okval3)
{ // Yippee! We made it!
return True; // <===== ONLY SUCCESS RETURN POINT
}
}
}
// Houston, we had a problem.
return False; // <===== ONLY FAIL RETURN POINT
}
In the case where the "else
" matters, it's a similar unwrapping, but we maintain ONLY two return points:
const Bool funcFoo(int someval, int someval2, int someval3)
{
if(someval == okval)
{ // We're ok
if(someval2 == okval2)
{ // Still ok.
if(someval3 == okval3)
{ // Yippee! We made it!
return True; // <===== ONLY SUCCESS RETURN POINT
}
else
{ // someval3 is bad.
//...maybe handle, not return.
}
}
else
{ // someval2 is bad.
// ...maybe handle, not return.
}
}
else
{ // someval is bad.
// ...maybe handle, not return.
}
// Houston, we had a problem.
return False; // <===== ONLY FAIL RETURN POINT
}
A couple things to mention:
- One return point is best. Two return points are acceptable if they are obvious (your errors typically mandate a return, or a failure-to-go-on).
- Sometimes the "
else
" is for debugging purposes only, at which point I wrap them in#ifdef _DEBUG ... #endif
- Sometimes the "test" should be for success, and sometimes for failure, depending on which is most appropriate for nesting.
- This approach (nested testing) is sometimes tied to sequential testing. However, nested testing is generally preferred.
I'd rather use something like this:
if (test1 == failed)
{
// print error;
// exit;
}
else if (test2 == failed)
{
// print error;
// exit;
}
else
{
// ... and so on...
}
It's more readable and it limits indentation. It also clearly shows me that if one condition fails, it's going to try all others until it finally fails; there's no chance of having 2 conditions fulfilled at the same time.
I vote for method 2. As you mention, the error handling in method 1 obscures the logic of the "real" algorithm.
精彩评论