Exception handling in C - What use of setjmp () returns 0?

I have a few questions regarding the use of setjmp / longjmp -

  • What is the use of setjmp (jmp ___ buf stackVariables) that returns 0. This is the default value that we cannot influence.

  • The only value of setjmp (stackVariables) is to push the stack on the Variables stack. And basically 0 tells us if stack stack_variance is successful.

  • This is one case when a value returns to zero (any non-zero value) when you return from longjmp. What returns from lomgjmp when you return from longjmp when your exception is handled. This setting is very confusing.

  • Can someone tie him up to try / throw and catch. And it would be really great if good examples of setjmp / longjmp were presented.

  • Longjmp is like throw, and it is called right after the place where the exception can be raised.

Thanks.

+6
c stack exception-handling
source share
4 answers

The C99 specification gives:

If the return is from a direct call, the setjmp macro returns 0. 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 zero indicates that you called setjmp first time, and nonzero indicates that it returns with longjmp .

  1. It pushes the current state of the program. After longjmp, the state is restored, control returns to the called point, and the return value is nonzero.

  2. There are no exceptions in C. It looks like a fork , returning different values ​​depending on whether you are in the original process or the second process that inherited the environment if you are familiar with this.

  3. try / catch in C ++ will invoke destructors on all automatic objects between the throw and the trick. setjmp / longjmp will not call destructors, since they do not exist in C. Thus, you yourself, if you call free on everything that you have malloc ed in average time.

With this caveat:

 #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" ); } } 

roughly equivalent

 #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 case of C, you need to do explicit memory management (although you can usually free it in a function that was malloc'd before calling longjmp, as that makes life easier)

+10
source share

setjmp is used to place the marker where the longjump call should return, it returns 0 if it is called directly, it returns 1 if it is called because longjmp is called for that setjmp.

You should think of setjmp as something that can usually be called and does nothing (returning 0) in normal operation, but returns 1, and it is indirectly called (and returns from there) when a long jump is called. I know what you mean, confusing, because it really is confusing.

This is an example provided by wikipedia:

 #include <stdio.h> #include <setjmp.h> static jmp_buf buf; void second(void) { printf("second\n"); // prints longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1 } void first(void) { second(); printf("first\n"); // does not print } int main() { if ( ! setjmp(buf) ) { first(); // when executed, setjmp returns 0 } else { // when longjmp jumps back, setjmp returns 1 printf("main"); // prints } return 0; } 

Can you figure it out? When the setjmp program starts, it runs in main and returns 0 (because it is called directly), so first is called, which calls second , and then it comes longjmp , which switches the context, returning to where setjmp , but this time, since it returns from the jump, and it is indirectly called the function returns 1.

A useful thing about the setjmp / longjmp approach is that you can handle error situations without having to keep the flag between function calls (especially when you have a lot, think of a recursive procedure for checking types in the compiler). If something goes wrong, as a rule, in the method of checking the call stack on the stack, you must return the flag and continue to return it to warn the caller that the typecheck check failed. With longjmp, you simply exit and handle the error without worrying about passing the flags back. The only problem is that this leads to a context switch that does not care about the standard freeing of stack / heap memory, so you have to handle it yourself.

+6
source share

The first part is almost simple: when you do longjmp, you end up exactly after setjmp. If the return value is 0, it means that you just did setjmp; if it is non-zero, you know that you have a long mix there from another place. This information is often useful for monitoring what your code does after that.

setjmp / longjmp are the old ancestors of throw / catch. setjmp / longjmp are defined in C, whereas throw / catch is a more “modern” mechanism for error recovery in more object-oriented languages ​​such as C ++.

the longjmp call says: “I think something is wrong here, help, get me out of here - I'm too embarrassed to clear myself after myself and return through a bunch of function calls, and if so, just bring me back where the world is again was fine right after the last setjmp. "

throw says almost the same thing, except that it is more clearly and cleanly supported in the syntax. In addition, although longjmp can lead you to almost anywhere in the program (wherever you did setjmp), the cast ends right up in the call hierarchy where the cast is located.

+4
source share

Just add Pete Kirkham to the answer (and comment): since the C standard does not allow you to save the return value of setjmp, perhaps Pete's example can be changed instead of using a switch. It still demonstrates how to distinguish between different return values, but does not violate the standard.

 #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(void) { char* data = 0; switch(setjmp(env)) { case 0: { printf("setjmp returned 0\n"); foo(&data); break; } case 42: { printf("setjmp returned 42\n"); handle ( data ); break; } default: { printf("setjmp returned something else?\n"); } } 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"); } } 
0
source share

All Articles