ANSI C equivalent of try/catch?

12,321

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 gotos 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;
}
Share:
12,321

Related videos on Youtube

aiden
Author by

aiden

Updated on May 03, 2022

Comments

  • aiden
    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
      anijhaw over 13 years
      nicemice.net/cexcept something that might be useful
    • Steve Jessop
      Steve Jessop over 13 years
      This code is not C, ansi or otherwise. C does not have the :: scope operator.
    • Kel
      Kel over 13 years
      C 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
      josesuero over 13 years
      The 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
    Steve Townsend over 13 years
    Hmm, third downvote today. Any particular reason for this one? I thought this looked promising.
  • Hogan
    Hogan over 13 years
    +1 because the down vote was wrong... perfect link for the question
  • Steve Townsend
    Steve Townsend over 13 years
    @John Dibling - that goes without saying... Will keep an eye out, maybe just a bad day.
  • Nemanja Trifunovic
    Nemanja Trifunovic over 13 years
    By the time exceptions were introduced to C++, the C-preprocessor implementation was a history.
  • sbi
    sbi over 13 years
    IME the usual way to indicate errors or failure in C is to return a value that's ignored by the caller. :(
  • sbi
    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
    Jonathan Leffler over 13 years
    I 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
    dmckee --- ex-moderator kitten over 13 years
    Nice. You may need nested instances if you need to unwind stuff conditionally.
  • paercebal
    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... :(