ANSI C equivalent of try/catch?
Solution 1
Generally, you don't.
It's possible to use setjmp
and longjmp
to build something fairly similar to try/catch, although there's no such thing in C as destructors or stack unwinding, so RAII is out of the question. You could even approximate RAII with a so-called "cleanup stack" (see for example Symbian/C++), although it's not a very close approximation, and it's a lot of work.
The usual way to indicate errors or failure in C is to return a value indicating success status. Callers examine the return value and act accordingly. See for example the standard C functions: printf
, read
, open
, for ideas how to specify your functions.
When mixing C and C++ code, you must ensure that a C++ exception never reaches C code. When writing C++ functions that will be called from C, catch everything.
Solution 2
C does not support exception handling.
There is info on one approach to this problem here. This shows the simple setjmp/longjmp
approach but also provides a more sophisticated alternative, covered in depth.
Solution 3
There is the classic unwinding goto
s pattern:
FILE *if = fopen(...);
FILE *of = NULL;
if (if == NULL) return;
of = fopen(...);
if (of == NULL) goto close_if;
/* ...code... */
if (something_is_wrong) goto close_of;
/* ... other code... */
close_of:
fclose(of);
close_if:
fclose(if);
return state;
Alternately you can fake it in a limited way by isolating the "try" code in another function
int try_code(type *var_we_must_write, othertype var_we_only_read /*, ... */){
/* ...code... */
if (!some_condition) return 1;
/* ...code... */
if (!another_condition) return 2;
/* ...code... */
if (last_way_to_fail) return 4;
return 0;
}
void calling_routine(){
/* ... */
if (try_code(&x,y/*, other state */) ) {
/* do your finally here */
}
/* ... */
}
but neither approach is fully equivalent. You have to manage all the resources yourself, you don't get automatic rollback until a handler is found, and so on...
Solution 4
This is my implementation of an exception handling system in C: exceptions4c.
It's powered by macros, built on top of setjmp
and longjmp
and it is 100% portable ANSI C.
There you can also find a list of all the different implementations I know of.
Solution 5
One useful coding style I like to use is the following. I don't know if it has a particular name but I came across it when I was reverse engineering some assembly code into the equivalent C code. You do lose an indentation level but it's not such a big deal to me. Watch out for reviewer who will point out the infinite loop! :)
int SomeFunction() {
int err = SUCCESS;
do {
err = DoSomethingThatMayFail();
if (err != SUCCESS) {
printf("DoSomethingThatMayFail() failed with %d", err);
break;
}
err = DoSomethingElse();
if (err != SUCCESS) {
printf("DoSomethingElse() failed with %d", err);
break;
}
// ... call as many functions as needed.
// If execution gets there everything succeeded!
return SUCCESS;
while (false);
// Something went wrong!
// Close handles or free memory that may have been allocated successfully.
return err;
}
Related videos on Youtube
aiden
Updated on May 03, 2022Comments
-
aiden about 2 years
I have some C code I'm working with, and I'm finding errors when the code is running but have little info about how to do a proper try/catch (as in C# or C++).
For instance in C++ I'd just do:
try{ //some stuff } catch(...) { //handle error }
but in ANSI C I'm a bit lost. I tried some online searches but I don't see enough info about how to make it happen / figured I'd ask here in case anyone can point me in the right direction.
Here's the code I'm working with (fairly simple, recursive method) and would like to wrap with try/catch (or equivalent error-handling structure).
However my main question is simply how to do a try / catch in ANSI C...the implementation / example doesn't have to be recursive.
void getInfo( int offset, myfile::MyItem * item ) { ll::String myOtherInfo = item->getOtherInfo(); if( myOtherInfo.isNull() ) myOtherInfo = ""; ll::String getOne = ""; myfile::Abc * abc = item->getOrig(); if( abc != NULL ) { getOne = abc->getOne(); } for( int i = 0 ; i < offset ; i++ ) { printf("found: %d", i); } if( abc != NULL ) abc->release(); int childCount = item->getChildCount(); offset++; for( int i = 0 ; i < childCount ; i++ ) getInfo( offset, item->getChild(i) ); item->release(); }
-
anijhaw over 13 yearsnicemice.net/cexcept something that might be useful
-
Steve Jessop over 13 yearsThis code is not C, ansi or otherwise. C does not have the
::
scope operator. -
Kel over 13 yearsC does not have exceptions handling mechanism. All error handling is usually done with return values and errnum variable. BTW, it would be good to get some detailed expert comments of how error handling is done properly in C :)
-
josesuero over 13 yearsThe only language I know of which would compile the code posted by @aiden is C++. And if it is C++, you can just use
try
/catch
. If you actually have to write ANSI C code, then it looks like you'll have to rewrite your code to actually be valid C in addition to the suggestions made in the answers.
-
-
Steve Townsend over 13 yearsHmm, third downvote today. Any particular reason for this one? I thought this looked promising.
-
Hogan over 13 years+1 because the down vote was wrong... perfect link for the question
-
Steve Townsend over 13 years@John Dibling - that goes without saying... Will keep an eye out, maybe just a bad day.
-
Nemanja Trifunovic over 13 yearsBy the time exceptions were introduced to C++, the C-preprocessor implementation was a history.
-
sbi over 13 yearsIME the usual way to indicate errors or failure in C is to return a value that's ignored by the caller.
:(
-
sbi over 13 years@Nemanja: That is indeed true for the original cfront. Comeau C++, however, still outputs C code. (Because that makes for high portability.) But I doubt that this is anymore useful than assembler output of any other compiler: it's machine-generated code, and as such not for human consumption.
-
Jonathan Leffler over 13 yearsI believe exceptions were the straw that broke the camel's back, where the camel in question was the cfront C++ compiler. See Stroupstrup "Design & Evolution of C++".
-
dmckee --- ex-moderator kitten over 13 yearsNice. You may need nested instances if you need to unwind stuff conditionally.
-
paercebal over 13 years@sbi: IME, some people still believe the "return a value" is the way to go in C++, Java and C#, too...
:(