Our code (in a simple library implementation) is beginning to look like this:
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);
...
}
This is cumbersome and ugly. Is there a better way to do this ? Perhaps using the C preprocessor ? I was thinking something like:
CHECK callToUnderlyingLibrary1();
CHECK callToUnderlyingLibrary2();
CHECK callToUnderlyingLibrary3();
where the CHECK macro invokes the function and does the rudimentary error checking.
Are there preferred idiomatic ways of handling this ?
Errors can be returned as nil , and in fact, it's the default, or “zero”, value of on error in Go. This is important since checking if err != nil is the idiomatic way to determine if an error was encountered (replacing the try / catch statements you may be familiar with in other programming languages).
This method is also known as try-catch-finally In this method, in the try block the error-free code has been executed and if it has found some issue it will be handled in the catch block and finally block will be executed all the things at any cost.
Another macro-based approach which you can use to mitigate the shortcomings in C fairly easily:
#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)
Then to invoke it you have:
CHECK(doSomething1()); CHECK(doSomething2()); // etc.
For bonus points you could easily extend the CHECK macro to take a second argument y that is what to do on failure:
#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")):
Usually, in C, one uses goto
for error handling:
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;
}
This can be improved with macros and more clever instruction flow (to avoid repeating cleanup code), but I hope you see the point.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With