优雅的错误检查

Ren*_*Ren 25 c error-handling

我们的代码(在一个简单的库实现中)开始看起来像这样:

err = callToUnderlyingLibrary1();
if (err!=0) {
printf ("blah %d\n", err);
...
}

err = callToUnderlyingLibrary2();
if (err!=0) {
printf ("blah %d\n", err);
...
}

err = callToUnderlyingLibrary3();
if (err!=0) {
printf ("blah %d\n", err);
...
}
Run Code Online (Sandbox Code Playgroud)

这很麻烦,很丑陋.有一个更好的方法吗 ?也许使用C预处理器?我想的是:

CHECK callToUnderlyingLibrary1();
CHECK callToUnderlyingLibrary2();
CHECK callToUnderlyingLibrary3();
Run Code Online (Sandbox Code Playgroud)

CHECK宏调用函数并进行基本错误检查.

是否有首选的惯用方法来处理这个问题?

Ale*_* C. 16

通常,在C中,一个goto用于错误处理:

int foo()
{
    if (Function1() == ERROR_CODE) goto error;
    ...
    struct bar *x = acquire_structure;
    ...
    if (Function2() == ERROR_CODE) goto error0;
    ...

    release_structure(x);
    return 0;

error0:
    release_structure(x);

error:
    return -1;
}
Run Code Online (Sandbox Code Playgroud)

这可以通过宏和更聪明的指令流来改进(以避免重复清理代码),但我希望你明白这一点.

  • Macos中的Gotos :-)感谢您提醒我为什么在可能的情况下用C++编程! (6认同)
  • 这些`goto`不在宏中!:) (4认同)
  • @Roddy:如果您使函数简短并且有纪律,则此方法没有错。Gotos和宏在这里使用。 (2认同)

flu*_*ffy 14

另一种基于宏的方法,您可以使用它来轻松地缓解C中的缺点:

#define CHECK(x) do { \
  int retval = (x); \
  if (retval != 0) { \
    fprintf(stderr, "Runtime error: %s returned %d at %s:%d", #x, retval, __FILE__, __LINE__); \
    return /* or throw or whatever */; \
  } \
} while (0)
Run Code Online (Sandbox Code Playgroud)

然后调用它你有:

CHECK(doSomething1());
CHECK(doSomething2());
// etc.
Run Code Online (Sandbox Code Playgroud)

对于奖励积分,您可以轻松扩展CHECK宏以获取第二个参数y,即失败时该怎么做:

#define CHECK(x, y) do { \
  int retval = (x); \
  if (retval != 0) { \
    fprintf(stderr, "Runtime error: %s returned %d at %s:%d", #x, retval, __FILE__, __LINE__); \
    y; \
  } \
} while (0)

// We're returning a different error code
CHECK(someFunction1(foo), return someErrorCode);
// We're actually calling it from C++ and can throw an exception
CHECK(someFunction2(foo), throw SomeException("someFunction2 failed")):
Run Code Online (Sandbox Code Playgroud)


Fre*_*die 6

我认为你应该看看异常和异常处理.http://www.cplusplus.com/doc/tutorial/exceptions/

try{    
    callToUnderlyingLibrary1();
    callToUnderlyingLibrary2();
    callToUnderlyingLibrary3();
}catch(exception& e)
    //Handle exception
}
Run Code Online (Sandbox Code Playgroud)

如果出现错误,您的库函数可能会抛出异常

  • 我不会downvote,因为在你的答案后删除了C++标签.但这个问题涉及C,它没有"try/catch"结构. (8认同)
  • 对.我首先要包含C++标签.请不要低估这个适用于C++的答案. (3认同)
  • @Roddy:注意到.我认为这对代码库来说是一个很好的长期增强. (2认同)