I want to use setjmp/longjmp to reuse some code inside the main function (NOTE: this is only an exercise and not something I ever seriously plan on doing in the real world). The following code is what I've came up with:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmp_body, jmp_ret;
void func(void)
{
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
}
int main()
{
int x = 0;
if (setjmp(jmp_body) == 1) {
printf("Body %d\n", ++x);
longjmp(jmp_ret, 1);
}
func();
func();
func();
return 0;
}
The way I expected this code to work is the following:
main()
function is going to remember where the 'body' part is and skip it using if (setjmp(jmp_body) == 1)
.func()
call is going to temporarily jump to the body using longjmp(jmp_body)
after remembering where the body is supposed to return using if (setjmp(jmp_ret) == 0)
func()
call using longjmp(jmp_ret, 1)
func()
is just going to return to main()
as expected.Therefore, what I expected the code to print is the following:
Body 1
Body 2
Body 3
Instead, it loops forever continually executing the body which indicates to me the func()
call isn't returning where it's supposed to and instead might be returning above itself executing itself over and over again.
In comparison, the following code prints just what I expected:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jmp_body, jmp_ret;
int main()
{
int x = 0;
if (setjmp(jmp_body) == 1) {
printf("Body %d\n", ++x);
longjmp(jmp_ret, 1);
}
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
if (setjmp(jmp_ret) == 0)
longjmp(jmp_body, 1);
return 0;
}
What is it about putting if (setjmp(jmp_ret) == 0) longjmp(jmp_body, 1)
inside a function call that makes the original approach invalid?
TL/DR - you can't jump back into a function you jumped out of.
7.13.2.1 TheC 2011 Online Draftlongjmp
function
...
2 Thelongjmp
function restores the environment saved by the most recent invocation of thesetjmp
macro in the same invocation of the program with the correspondingjmp_buf
argument. If there has been no such invocation, or if the invocation was from another thread of execution, or if the function containing the invocation of thesetjmp
macro has terminated execution248) in the interim, or if the invocation of thesetjmp
macro was within the scope of an identifier with variably modified type and execution has left that scope in the interim, the behavior is undefined.
248) For example, by executing a return statement or because anotherlongjmp
call has caused a transfer to asetjmp
invocation in a function earlier in the set of nested calls.
When you execute longjmp(jump_body, 1);
in func
, you invalidate jump_ret
.
longjmp
isn't bidirectional - it unwinds the stack as though any of the function calls between the setjmp
and longjmp
never happened.