Error Handling In C Goto
Contents |
crystal-clear structure, without giving much thought to the often ugly topic of error handling. But unfortunately in programming, perhaps more than in any other kind of engineering, the devil is in the details. The handling of errors and of exceptions c irregular inputs and data usually requires more code than the straight-line algorithm for solving the problem error handling functions in c itself. This is a regrettable but unavoidable artifact of our craft. But wait, there's more. As difficult as error handling is, coupled with resource
Error Handling In Objective C
allocation and the need for robust deallocation it is nothing short of a huge headache. Fortunately, in newer high-level languages this is less of a problem because of automatic garbage collection. Also, C++ provides tolerably robust solutions in the form
C Error Handling Best Practices
of RAII. But as the title states, here I'm concerned with C, which doesn't have exceptions and destructors, so the issue is much more difficult. In this article I will argue that the much hated goto statement is a valuable tool for simplifying error-handling code in C. A simple case Here's a quote from the Wikipedia article on RAII: C requires significant administrative code since it doesn't support exceptions, try-finally blocks, or RAII at all. A typical approach is to separate c sharp error handling releasing of resources at the end of the function and jump there with gotos in the case of error. This way the cleanup code need not be duplicated. The code sample the article shows is this: int c_example() { int ret = 0; // return value 0 is success FILE *f = fopen("logfile.txt", "w+"); if (!f) return -1; if (fputs("hello logfile!", f) == EOF) { ret = -2; goto out; } // continue using the file resource // ... // Releasing resources (in reverse order) out: if (fclose(f) == EOF) ret = -3; return ret; } Sure, by inverting the logical comparison, this can be rewritten without a goto as follows: int c_example() { int ret = 0; // return value 0 is success FILE *f = fopen("logfile.txt", "w+"); if (!f) return -1; if (fputs("hello logfile!", f) != EOF) { // continue using the file resource } else { ret = -2; } if (fclose(f) == EOF) ret = -3; return ret; } Although we've gotten rid of the goto, IMHO this code isn't much cleaner. Note that we've just moved the mainline code into a condition. Will we do it for any error condition the function encounters? A thornier case Now consider this snippet: int foo(int bar) { int return_value = 0; allocate_resources_1(); if (!do_something(bar)) goto error_1; allocate_resources_2(); if (!init_stuff(bar)) goto error_2; allocate_resources_3(); if (!prepare_stuff(bar)) goto error_3; return_value = do_the_thing(bar); error_3: cleanup_3(); error_2: cleanup_2(); error_1: cleanup_1(); return re
here for a quick overview of the site Help Center Detailed answers to any questions you might have Meta Discuss the workings and policies of this site About Us Learn more about Stack Overflow the company Business Learn more about hiring developers or posting ads
C Error Handling Errno
with us Programmers Questions Tags Users Badges Unanswered Ask Question _ Programmers Stack Exchange is a error handling c programming question and answer site for professional programmers interested in conceptual questions about software development. Join them; it only takes a minute: Sign up Here's how c exit it works: Anybody can ask a question Anybody can answer The best answers are voted up and rise to the top Is this a decent use-case for goto in C? up vote 38 down vote favorite 9 I really hesitate to http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c ask this, because I don't want to "solicit debate, arguments, polling, or extended discussion" but I'm new to C and want to gain more insight into common patterns used in the language. I recently heard some distaste for the goto command, but I've also recently found a decent use-case for it. Code like this: error = function_that_could_fail_1(); if (!error) { error = function_that_could_fail_2(); if (!error) { error = function_that_could_fail_3(); ...to the n-th tab level! } else { // deal with error, clean http://programmers.stackexchange.com/questions/154974/is-this-a-decent-use-case-for-goto-in-c up, and return error code } } else { // deal with error, clean up, and return error code } If the clean-up part is all very similar, could be written a little prettier (my opinion?) like this: error = function_that_could_fail_1(); if(error) { goto cleanup; } error = function_that_could_fail_2(); if(error) { goto cleanup; } error = function_that_could_fail_3(); if(error) { goto cleanup; } ... cleanup: // deal with error if it exists, clean up // return error code Is this a common or acceptable use-case of goto in C? Is there a different/better way to do this? c design-patterns goto share|improve this question edited Jun 30 '12 at 13:21 Bill the Lizard 7,49683386 asked Jun 30 '12 at 1:49 Robz 9213910 2 See also this question (and my answer). –Keith Thompson Jun 30 '12 at 3:32 1 That's probably the one excuse for goto, of course if you really object you can use c++ and exceptions - but that's just goto with a sugar coating –Martin Beckett Jun 30 '12 at 3:37 1 @DeadMG You'd still end up with lots of nesting. –Izkata Jun 30 '12 at 3:40 4 @DeadMG: Using another language is not always an option. –Benjamin Kloster Jun 30 '12 at 11:38 10 I think with appropriate label naming, example may look quite decent: goto hell; –gnat Jun 30 '12 at 11:50 | show 8 more comments 12 Answers 12 active oldest votes up vote 27 do
single target inside a function) is just perfect for C error handling code. Don't be misguided by a silly principle of goto's being always bad. They get the job done https://news.ycombinator.com/item?id=3883310 in the cleanest possible way, so you should use them for doing cleanups.The examples did not have any resources to clean up, and that is what makes error handling in C painful. In the absence of any cleanup routines, http://embeddedgurus.com/stack-overflow/2010/02/goto-heresy/ this will do: return ( do_something() == SUCCESS && do_something_else() == SUCCESS && do_final_thing() == SUCCESS) ? SUCCESS : FAILURE; Of course, once you add resources to clean up or error codes that are meaningful (not just success/fail) error handling error handling gets more painful.You should not try to perfect something as mundane as error handling. Just write the damn code and get over it. tspiteri 1631 days ago Why should the goto be to one single target? Multiple goto statements are good for multiple clean ups without adding indentation levels and without having artificially long logic ands. For example: int init_abc() { if (!init_a()) goto err_a; if (!init_b()) goto err_b; if (!init_c()) goto err_c; error handling in return 1; err_c: cleanup_b(); err_b: cleanup_a(); err_a: return 0; } seems to be the cleanest way to do what it does in C. For what it's worth, it is the way a lot of error handling is done in the Linux kernel. exDM69 1631 days ago I guess it's fine to use multiple targets too. However, usually you can get away with one, because free(NULL) and similar cleanups tend to be no-ops. So you have something like: char *foo = 0, *bar = 0; if((foo = malloc(X)) == NULL || (bar = malloc(Y)) == NULL) goto cleanup; make_me_millions(foo, bar); cleanup: free(bar); free(foo); In this case, and many cases like it, there's no need to have two jump targets, because one is good enough. You'll have to declare the variables early on anyway to avoid warnings/errors from definitions that cross jump labels.So there's probably nothing wrong with multiple jump targets but that might not be needed with well-behaving cleanup functions. adestefan 1631 days ago because free(NULL) and similar cleanups tend to be no-ops. So you have something likeYou really need to check the specification on each function. free is defined that free(NULL) is no-op, but there are other things where that is not the case. Also, that code is not portable since NULL does not have to be 0. cdellin 1631 days ago Just a
» Goto heresy Monday, February 1st, 2010 by Nigel Jones Today's post is prompted by an email I received from Michael Burns. With his permission I have reproduced his email below. Hi Nigel, What is your opinion on the usage of goto in C? Sometimes when a routine has many conditions [usually for error handling] I have used a do {..} while(0); loop with breaks thus avoiding both deep nesting and repeated checks with a status variable. For example: unsigned int XXX_ExampleRoutine (unsigned int XXX_instance, unsigned int *XXX_handle) { unsigned int status; do { if (!XXX_IsValidXXXInstance (XXX_instance)) { status = XXX_INVALID_INSTANCE; break; } if (XXX_handle == NULL) { status = XXX_INVALID_ARGUMENT; break; } status = XXX_AddRequest (XXX_instance, XXX_handle); if (status != XXX_STATUS_OK) { break; } etc } while (0); return status; } But perhaps the do {..} while(0); loop is just an excuse not to use goto? My (slightly edited) response to him was as follows: I rarely use a goto statement. While I dislike them for their potential abuse (for example a number of years ago I looked at a Flash driver from AMD that was absolutely littered with them), I also think they have their place. Furthermore I think folks that scream ‘the goto statement is banned’ and then happily allow the use of ‘break’ and ‘continue’ are deluding themselves. Turning to your example code. As you have pointed out, coding this without using ‘break’ or ‘goto’ can rapidly lead to code that is a nightmare to follow. Indeed once one gets beyond about four or five tests of the type you are performing, I’d say that the code becomes impossible to follow unless you use either the style you have espoused or a goto statement. I’d also make the case that in this situation a goto is actually better. To illustrate my point, I have modified your code slightly, in much the way someone might who wasn’t paying attention: unsigned int XXX_ExampleRoutine (unsigned int XXX_instance, unsigned int *XXX_handle) { unsigned int status; do { if (!XXX_IsValidXXXInstance (XXX_instance)) { status = XXX_INVALID_INSTANCE; break; } if (XXX_handle == NULL) { status = XXX_INVALID_ARGUMENT; break; } do { status = XXX_AddRequest (XXX_instance, XXX_handle); if (status == XXX_STATUS_BAD) { break; } } while (status == XXX_SOME_STATUS); etc } while (0); return status; } In this case, the break wouldn’t work as desired, whereas if you had coded it with a goto, the code would still work as intended. I guess the bottom line for me is that K&R put a