Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception Handling in C - What is the use of setjmp() returning 0?

I have a few questions relating to setjmp/longjmp usage -

  1. What is the use of setjmp(jmp___buf stackVariables) returning 0. It is a default, which we cannot influence.

  2. Is the only significance of setjmp(stackVariables) is to push the stack in stackVariables. And basically 0 tells us if the stack was pushed on stack_variables successfully.

  3. Their is one occasion when the value is non-zero (any non-zero) when you return from a longjmp. What is returning from a lomgjmp, when do you return from longjmp, when your exception is handled. This is setup is really confusing.

  4. Can some please relate it to try/throw and catch. And would be really great, if some good examples of setjmp/longjmp could be provided.

  5. Is longJmp like throw, and it is called just after the place where exception can be raised.

Thanks.

like image 544
Vivek Sharma Avatar asked Nov 07 '09 11:11

Vivek Sharma


People also ask

What does setjmp return?

The setjmp() function saves various information about the calling environment (typically, the stack pointer, the instruction pointer, possibly the values of other registers and the signal mask) in the buffer env for later use by longjmp(). In this case, setjmp() returns 0.

What is setjmp used for?

setjmp saves the current environment (the program state), at some point of program execution, into a platform-specific data structure ( jmp_buf ) that can be used at some later point of program execution by longjmp to restore the program state to that saved by setjmp into jmp_buf .

What is the use of setjmp and longjmp functions with examples?

setjmp and longjmp are a pair of C function facilitating cross-procedure transfer of control. Typically they are used to allow resumption of execution at a known good point after an error. Both take as first argument a buffer, which is used to hold the machine state at the jump destination.

What is exception handling C?

Exception handling is a mechanism that separates code that detects and handles exceptional circumstances from the rest of your program. Note that an exceptional circumstance is not necessarily an error. When a function detects an exceptional situation, you represent this with an object.


1 Answers

The C99 spec gives:

If the return is from a direct invocation, the setjmp macro returns the value zero. If the return is from a call to the longjmp function, the setjmp macro returns a nonzero value.

So the answer to 1 is that a zero indicates you have called setjmp the first time, and non-zero indicates it is returning from a longjmp.

  1. It pushes the current program state. After a longjmp, the state is restored, control returns to the point it was called, and the return value is non-zero.

  2. There are no exceptions in C. It's sort-of similar to fork returning different values depending whether you're in the original process, or a second process which has inherited the environment, if you're familiar with that.

  3. try/catch in C++ will call destructors on all automatic objects between the throw and the catch. setjmp/longjmp will not call destructors, as they don't exist in C. So you are on your own as far as calling free on anything you've malloced in the mean time.

With that proviso, this:

#include <stdio.h>
#include <setjmp.h>
#include <string.h>
#include <stdlib.h>

void foo ( char** data ) ;
void handle ( char* data ) ;
jmp_buf env;

int main ()
{
    char* data = 0;

    int res = setjmp ( env ); 
    // stored for demo purposes. 
    // in portable code do not store 
    // the result, but test it directly.

    printf ( "setjmp returned %d\n", res );

    if ( res == 0 )
        foo ( &data );
    else
        handle ( data );

    return 0;
}


void foo ( char** data )
{
    *data = malloc ( 32 );

    printf ( "in foo\n" );

    strcpy ( *data, "Hello World" );

    printf ( "data = %s\n", *data );

    longjmp ( env, 42 );
}

void handle ( char* data )
{
    printf ( "in handler\n" );

    if ( data ) {
        free ( data );
        printf ( "data freed\n" );
    }
}

is roughly equivalent to

#include <iostream>

void foo ( ) ;
void handle ( ) ;

int main ()
{
    try {
        foo ();
    } catch (int x) {
        std::cout << "caught " << x << "\n";
        handle ();
    }

    return 0;
}

void foo ( )
{
    printf ( "in foo\n" );

    std::string data = "Hello World";

    std::cout << "data = " << data << "\n";

    throw 42;
}

void handle ( )
{
    std::cout << "in handler\n";
}

In the C case, you have to do explicit memory management (though normally you'd free it in the function which malloc'd it before calling longjmp as it makes life simpler)

like image 86
Pete Kirkham Avatar answered Sep 21 '22 11:09

Pete Kirkham