2011-05-14 77 views
3

可能重复:
Error handling in C code处理C语言错误的样式?

你好的人。我使用C来处理一些小型项目,我看到它是如何的,因为它没有专门的错误处理结构,所以我必须用额外的条件块来污染我的算法。我的问题是你如何更好地处理错误,并说明为什么。我在两种方式之间撕裂......如果你有第三种方式,请发布。谢谢。

/////////////////////////////////////////// 
// method 1 

// stuff that 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... 
+0

我会建议使用第二种风格,因为它不会影响您的意图。但我想这只是一个问题。 – Constantinius 2011-05-14 21:22:35

回答

0

我宁愿使用这样的:

if (test1 == failed) 
{ 
    // print error; 
    // exit; 
} 
else if (test2 == failed) 
{ 
    // print error; 
    // exit; 
} 
else 
{ 
    // ... and so on... 
} 

这是更具可读性和它限制缩进。这也清楚地表明,如果一个条件失败了,它将尝试所有其他条件直到最终失败;没有机会同时满足2个条件。

+0

然而,有更多的东西可以出错,所以你不能以一种很好的方式真正做到这一点。 – 2011-05-14 21:25:14

+0

总有更多的东西可能会出错:)。 – alex 2011-05-14 21:28:19

5

有些人不会同意我这一点,但我使用goto's。每个函数里面,最后我在它看起来像这样

if (0) 
{ 
ERROR: 
    // Handle errors, and exit/return after potentially freeing resources 
} 

然后我用if (something_bad) goto ERROR;没有别人的或其他的东西到底有块。

许多人不喜欢goto的,但这是这样做的方式,而不是重复代码。如果你真的坚持不使用goto语句的我会做到这一点:

#define LOCAL_ASSERT(COND) if (COND) { \ 
    /* Handle errors, and exit/return after potentially freeing resources */ \ 
} 

添加在每个函数的开头定义它,然后添加在函数的末尾添加#undef LOCAL_ASSERT。这允许在每个函数处进行不同的错误处理,而不用不同的宏名称来污染整个程序。

然后我简单地使用LOCAL_ASSERT(cond)无处不在。

编辑:使自己更清晰,这是为了节省多次编写错误处理代码。如果你想要小的定制,很容易设置一个错误变量字符串(或者将它作为宏参数添加)。我只是不喜欢这样的事情。我通常做

// method 1 
if (error) goto ERROR; // no else 

// method 2 
LOCAL_ASSERT(cond); 

Elses会污染你的代码,并需要更多的缩进,这有时是烦人的。

0

我对方法2投了票。正如你所提到的,方法1中的错误处理掩盖了“真实”算法的逻辑。

1

我知道这是用户偏好一些,但我确实努力从每个功能建立退出点,或至多两个出口点(但必须是明显和容易断点):

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 
} 

在有“else”的问题,这是一个类似解缠的情况,但我们只保留两个返回点:

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 
} 

几件事情要提:

  1. 一个返回点是最好的。两个 返回点是可以接受的,如果他们 是显而易见的(您的错误通常要求退货或失败继续)。
  2. 有时“else”仅用于 调试的目的,在此 点我包起来#ifdef _DEBUG ... #endif
  3. 有时“测试”应该是 成功,有时失败, 取决于哪个是最 适合嵌套。
  4. 此方法(嵌套测试)是 有时与连续测试 连接。但是,嵌套测试通常优选为 。