Error handling code for any general function follows this template
Two questions from my end--
What should be the default FAILURE value? (1 to keep up with the main or 0, or -1 to avoid all the confusion)
What should be the initial value of status? (FAIL or PASS)
Code:
#define FAILURE 0 //or shall it be 1 for success and 0 for failure
#define SUCCESS 1
int DoSomething() {
int status = FAILURE; //or shall we assign success by default?
if (error1)
return FAIL_A
if (error2)
return FAIL_B
return SUCCESS;
}
int GetItDone() {
status = FAIL;
Status = DoSomething();
if (PASS != status) //likewise many calls can happen later
goto END;
END:
return status;
}
The status bubble up through function calls.
The convention is 0 for success, negative values for various failures, and positive values for predicated successes.
Of these, returning 0 for success is the most frequently observed: doing otherwise would be idiosyncratic.
As for your code, setting the status to a failure code initially and changing it to success as appropriate will afford more program stability.
Returning 0 for success lets you return different values in case of failure
#define SUCCESS 0
#define FAILURE_CASE_1 -1
#define FAILURE_CASE_2 -2
I am not able to compile my code, I am getting error: control may reach the end of a non-void function
/**
* Returns true if value is in array of n values, else false.
*/
bool search(int value, int values[], int n)
{
//Binary search algorithm
int first = 0;
int last = n-1;
int middle = (first+last)/2;
if (n<1)
return false;
else
{
while (first <= last)
{
if (values[middle]==value)
return true;
else if(values[middle]<value)
first=middle+1;
else if (values[middle]>value)
{
last=middle-1;
}
middle=(first+last)/2;
}
}
if (first>last)
return false;
}
Can anyone look through my code and help me figure out where the issue is? I am struggling to see it myself! From my point of view, this function returns true or false
Your return type of bool means that your function is always expected to return a boolean value before it exits, no matter which path of execution it takes. As it stands now, it appears on inspection that you can "fall through" the last if and never hit a return statement. To verify otherwise would require stepping through your logic in a way the compiler cannot reasonably be expected to do. At the end simply change to say:
if (first>last) {
return false;
} else {
return true;
}
Or more concisely:
return (first > last) ? false : true;
In your code it's not possible for the function to fall off the end.
However, the compiler is not required to accurately diagnose whether a function can get to the end or not. In general, to do so would require solving the halting problem.
Instead, as a practical measure, your compiler is doing some basic checks and warning because it sees the if ( first > last ) return false;, it didn't do enough code analysis to determine that this branch can never be reached unless first > last.
To suppress this warning you could just remove the line if ( first > last ). BTW this is a warning, not an error; so it should not prevent your compilation.
int status;
status=hsearch_r(wishFind,FIND,&(h->retElem),(h->htab));
print("Debug: status is %d\n",status);
the result show status is -8400
but the wishFind is not in h->htab.
I think status need to be 0.
it's confused me that status is -8400.
Thanks!
From the manpage:
hsearch_r() returns nonzero on success, and 0 on error.
That means it's allowed to return any non-zero value on success so you need to cater for that:
if (status == 0) {
// failure
} else {
// success
}
If what you're looking for really isn't in the hash table, you have a problem quite separate from the code you've shown us.
Most of the places I have seen the return code values are done like this,
for success status return , #define SUCCESS 0 and other no zero numbers for all other error cases.
My question is , why we selecetd zero for SUCCESS case? Is there any specific programming best practice concerns for that?
/R
It's an old C habit to return 0 for success and some other code for errors, so you can say:
int error = do_stuff();
if (error) {
handle_error(error);
}
However, predicates usually work the other way around, returning 1 for "success" (or true from <stdbool.h>).
You have to differenciate between different errors, there can be MaxInt - 1 different ones.
If 0 was an error and 1 was success, how could you tell the difference between all errors?
Zero often means success because zero is the only integer value that evaluates to false. All other integer values evaluate to true and they are meant for various error codes.
It might seem a bit weird and logically inverted, but because success is just success and errors can be different, the above convention is chosen often.
In fact, this is the most rational convention if the return value of a function is used not only as a success/failure indicator, but as an error code too. If the error code is stored, say in an additional output parameter, then returning 1 for success and 0 for failure makes more sense.
Imagine what the condition would be in the case of 0 being success:
if (errcode = func()) {
/* error handling */
}
versus the more cumbersome:
if ((errcode = func()) != 1) {
/* error handling */
}
This is an operating system convention.
http://en.wikipedia.org/wiki/Exit_status
I'm trying to learn C by writing a simple parser / compiler. So far its been a very enlightening experience, however coming from a strong background in C# I'm having some problems adjusting - in particular to the lack of exceptions.
Now I've read Cleaner, more elegant, and harder to recognize and I agree with every word in that article; In my C# code I avoid throwing exceptions whenever possible, however now that I'm faced with a world where I can't throw exceptions my error handling is completely swamping the otherwise clean and easy-to-read logic of my code.
At the moment I'm writing code which needs to fail fast if there is a problem, and it also potentially deeply nested - I've settled on a error handling pattern whereby "Get" functions return NULL on an error, and other functions return -1 on failure. In both cases the function that fails calls NS_SetError() and so all the calling function needs to do is to clean up and immediately return on a failure.
My issue is that the number of if (Action() < 0) return -1; statements that I have is doing my head in - it's very repetitive and completely obscures the underlying logic. I've ended up creating myself a simple macro to try and improve the situation, for example:
#define NOT_ERROR(X) if ((X) < 0) return -1
int NS_Expression(void)
{
NOT_ERROR(NS_Term());
NOT_ERROR(Emit("MOVE D0, D1\n"));
if (strcmp(current->str, "+") == 0)
{
NOT_ERROR(NS_Add());
}
else if (strcmp(current->str, "-") == 0)
{
NOT_ERROR(NS_Subtract());
}
else
{
NS_SetError("Expected: operator");
return -1;
}
return 0;
}
Each of the functions NS_Term, NS_Add and NS_Subtract do a NS_SetError() and return -1 in the case of an error - its better, but it still feels like I'm abusing macros and doesn't allow for any cleanup (some functions, in particular Get functions that return a pointer, are more complex and require clean-up code to be run).
Overall it just feels like I'm missing something - despite the fact that error handling in this way is supposedly easier to recognize, In many of my functions I'm really struggling to identify whether or not errors are being handled correctly:
Some functions return NULL on an error
Some functions return < 0 on an error
Some functions never produce an error
My functions do a NS_SetError(), but many other functions don't.
Is there a better way that I can structure my functions, or does everyone else also have this problem?
Also is having Get functions (that return a pointer to an object) return NULL on an error a good idea, or is it just confusing my error handling?
It's a bigger problem when you have to repeat the same finalizing code before each return from an error. In such cases it is widely accepted to use goto:
int func ()
{
if (a() < 0) {
goto failure_a;
}
if (b() < 0) {
goto failure_b;
}
if (c() < 0) {
goto failure_c;
}
return SUCCESS;
failure_c:
undo_b();
failure_b:
undo_a();
failure_a:
return FAILURE;
}
You can even create your own macros around this to save you some typing, something like this (I haven't tested this though):
#define CALL(funcname, ...) \
if (funcname(__VA_ARGS__) < 0) { \
goto failure_ ## funcname; \
}
Overall, it is a much cleaner and less redundant approach than the trivial handling:
int func ()
{
if (a() < 0) {
return FAILURE;
}
if (b() < 0) {
undo_a();
return FAILURE;
}
if (c() < 0) {
undo_b();
undo_a();
return FAILURE;
}
return SUCCESS;
}
As an additional hint, I often use chaining to reduce the number of if's in my code:
if (a() < 0 || b() < 0 || c() < 0) {
return FAILURE;
}
Since || is a short-circuit operator, the above would substitute three separate if's. Consider using chaining in a return statement as well:
return (a() < 0 || b() < 0 || c() < 0) ? FAILURE : SUCCESS;
One technique for cleanup is to use an while loop that will never actually iterate. It gives you goto without using goto.
#define NOT_ERROR(x) if ((x) < 0) break;
#define NOT_NULL(x) if ((x) == NULL) break;
// Initialise things that may need to be cleaned up here.
char* somePtr = NULL;
do
{
NOT_NULL(somePtr = malloc(1024));
NOT_ERROR(something(somePtr));
NOT_ERROR(somethingElse(somePtr));
// etc
// if you get here everything's ok.
return somePtr;
}
while (0);
// Something went wrong so clean-up.
free(somePtr);
return NULL;
You lose a level of indentation though.
Edit: I'd like to add that I've nothing against goto, it's just that for the use-case of the questioner he doesn't really need it. There are cases where using goto beats the pants off any other method, but this isn't one of them.
You're probably not going to like to hear this, but the C way to do exceptions is via the goto statement. This is one of the reasons it is in the language.
The other reason is that goto is the natural expression of the implementation of a state machine. What common programming task is best represented by a state machine? A lexical analyzer. Look at the output from lex sometime. Gotos.
So it sounds to me like now is the time for you to get chummy with that parriah of language syntax elements, the goto.
Besides goto, standard C has another construct to handle exceptional flow control setjmp/longjmp. It has the advantage that you can break out of multiply nested control statements more easily than with break as was proposed by someone, and in addition to what goto provides has a status indication that can encode the reason for what went wrong.
Another issue is just the syntax of your construct. It is not a good idea to use a control statement that can inadvertibly be added to. In your case
if (bla) NOT_ERROR(X);
else printf("wow!\n");
would go fundamentally wrong. I'd use something like
#define NOT_ERROR(X) \
if ((X) >= 0) { (void)0; } \
else return -1
instead.
THis must be thought on at least two levels: how your functions interact, and what you do when it breaks.
Most large C frameworks I see always return a status and "return" values by reference (this is the case of the WinAPI and of many C Mac OS APIs). You want to return a bool?
StatusCode FooBar(int a, int b, int c, bool* output);
You want to return a pointer?
StatusCode FooBar(int a, int b, int c, char** output);
Well, you get the idea.
On the calling function's side, the pattern I see the most often is to use a goto statement that points to a cleanup label:
if (statusCode < 0) goto error;
/* snip */
return everythingWentWell;
error:
cleanupResources();
return somethingWentWrong;
What about this?
int NS_Expression(void)
{
int ok = 1;
ok = ok && NS_Term();
ok = ok && Emit("MOVE D0, D1\n");
ok = ok && NS_AddSub();
return ok
}
The short answer is: let your functions return an error code that cannot possibly be a valid value - and always check the return value. For functions returning pointers, this is NULL. For functions returning a non-negative int, it's a negative value, commonly -1, and so on...
If every possible return value is also a valid value, use call-by-reference:
int my_atoi(const char *str, int *val)
{
// convert str to int
// store the result in *val
// return 0 on success, -1 (or any other value except 0) otherwise
}
Checking the return value of every function might seem tedious, but that's the way errors are handled in C. Consider the function nc_dial(). All it does is checking its arguments for validity and making a network connection by calling getaddrinfo(), socket(), setsockopt(), bind()/listen() or connect(), finally freeing unused resources and updating metadata. This could be done in approximately 15 lines. However, the function has nearly 100 lines due to error checking. But that's the way it is in C. Once you get used to it, you can easily mask the error checking in your head.
Furthermore, there's nothing wrong with multiple if (Action() == 0) return -1;. To the contrary: it is usually a sign of a cautious programmer. It's good to be cautious.
And as a final comment: don't use macros for anything but defining values if you can't justify their use while someone is pointing with a gun at your head. More specifically, never use control flow statements in macros: it confuses the shit out of the poor guy who has to maintain your code 5 years after you left the company. There's nothing wrong with if (foo) return -1;. It's simple, clean and obvious to the point that you can't do any better.
Once you drop your tendency to hide control flow in macros, there's really no reason to feel like you're missing something.
A goto statement is the easiest and potentially cleanest way to implement exception style processing. Using a macro makes it easier to read if you include the comparison logic inside the macro args. If you organize the routines to perform normal (i.e. non-error) work and only use the goto on exceptions, it is fairly clean for reading. For example:
/* Exception macro */
#define TRY_EXIT(Cmd) { if (!(Cmd)) {goto EXIT;} }
/* My memory allocator */
char * MyAlloc(int bytes)
{
char * pMem = NULL;
/* Must have a size */
TRY_EXIT( bytes > 0 );
/* Allocation must succeed */
pMem = (char *)malloc(bytes);
TRY_EXIT( pMem != NULL );
/* Initialize memory */
TRY_EXIT( initializeMem(pMem, bytes) != -1 );
/* Success */
return (pMem);
EXIT:
/* Exception: Cleanup and fail */
if (pMem != NULL)
free(pMem);
return (NULL);
}
It never occurred to me to use goto or do { } while(0) for error handling in this way - its pretty neat, however after thinking about it I realised that in many cases I can do the same thing by splitting the function out into two:
int Foo(void)
{
// Initialise things that may need to be cleaned up here.
char* somePtr = malloc(1024);
if (somePtr = NULL)
{
return NULL;
}
if (FooInner(somePtr) < 0)
{
// Something went wrong so clean-up.
free(somePtr);
return NULL;
}
return somePtr;
}
int FooInner(char* somePtr)
{
if (something(somePtr) < 0) return -1;
if (somethingElse(somePtr) < 0) return -1;
// etc
// if you get here everything's ok.
return 0;
}
This does now mean that you get an extra function, but my preference is for many short functions anyway.
After Philips advice I've also decided to avoid using control flow macros as well - its clear enough what is going on as long as you put them on one line.
At the very least Its reassuring to know that I'm not just missing something - everyone else has this problem too! :-)
Use setjmp.
http://en.wikipedia.org/wiki/Setjmp.h
http://aszt.inf.elte.hu/~gsd/halado_cpp/ch02s03.html
http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
#include <setjmp.h>
#include <stdio.h>
jmp_buf x;
void f()
{
longjmp(x,5); // throw 5;
}
int main()
{
// output of this program is 5.
int i = 0;
if ( (i = setjmp(x)) == 0 )// try{
{
f();
} // } --> end of try{
else // catch(i){
{
switch( i )
{
case 1:
case 2:
default: fprintf( stdout, "error code = %d\n", i); break;
}
} // } --> end of catch(i){
return 0;
}
#include <stdio.h>
#include <setjmp.h>
#define TRY do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){
#define CATCH } else {
#define ETRY } }while(0)
#define THROW longjmp(ex_buf__, 1)
int
main(int argc, char** argv)
{
TRY
{
printf("In Try Statement\n");
THROW;
printf("I do not appear\n");
}
CATCH
{
printf("Got Exception!\n");
}
ETRY;
return 0;
}