Поскольку вы вызываете неопределенное поведение, нормально, что один компилятор аварийно завершит работу, а другой будет работать. И то, и другое правильно - вот в чем прелесть неопределенного поведения.
Проблема в том, что сохраненный контекст - jmp_buf
- остается действительным только до тех пор, пока функция, вызвавшая setjmp()
для его установки, не вернулась.
Стандарт C99 (более не действующий стандарт, но вряд ли эта формулировка существенно изменилась) гласит:
§7.13.2.1 Функция longjmp
Функция longjmp
восстанавливает среду, сохраненную последним вызовом
макрос setjmp
в том же вызове программы с соответствующим
jmp_buf
аргумент. Если такого вызова не было, или если функция, содержащая
вызов макроса setjmp
завершил выполнение 208) в промежуточный период или, если
вызов макроса setjmp
находился в области идентификатора с переменной
измененный тип и выполнение оставили эту область в промежутке, поведение не определено.
208) Например, путем выполнения оператора return
или потому, что другой вызов longjmp
вызвал
перейти к вызову setjmp
в функции ранее в наборе вложенных вызовов.
Ваш код выходит из action_1()
почти сразу, что делает jmp_buf
сохраненным setjmp()
бесполезным.
Я создал эту маленькую демонстрацию setjmp()
и longjmp()
пару лет назад. Это может помочь вам.
/*
@(#)File: $RCSfile: setjmp.c,v $
@(#)Version: $Revision: 1.1 $
@(#)Last changed: $Date: 2009/10/01 16:41:04 $
@(#)Purpose: Demonstrate setjmp() and longjmp()
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 2009
*/
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
static jmp_buf target_location;
static void do_something(void)
{
static int counter = 0;
if (++counter % 10 == 0)
printf("---- doing something: %3d\n", counter);
if (counter % 1000 == 0)
{
printf("||-- doing_something: calling longjmp() with value -1\n");
longjmp(target_location, -1);
}
}
static void do_something_else(int i, int j)
{
printf("-->> do_something_else: (%d,%d)\n", i, j);
do_something();
if (i > 2 && j > 2 && j % i == 2)
{
printf("||-- do_something_else: calling longjmp() with value %d\n", (i + j) % 100);
longjmp(target_location, (i + j) % 100);
}
printf("<<-- do_something_else: (%d,%d)\n", i, j);
}
static void doing_stuff(void)
{
int i;
printf("-->> doing_stuff()\n");
for (i = rand() % 15; i < 30; i++)
{
int j;
do_something();
for (j = rand() % 10; j < 20; j++)
{
do_something_else(i, j);
}
}
printf("<<-- doing_stuff()\n");
}
static void manage_setjmp(void)
{
printf("-->> manage_setjmp()\n");
switch (setjmp(target_location))
{
case 0:
/* Initial return - get on with doing stuff */
doing_stuff();
break;
case -1:
/* Error return - terminate */
printf("<<-- manage_setjmp() - error return from setjmp()\n");
return;
default:
/* NB: not officially possible to assign the return from setjmp() */
printf("---- manage_setjmp() - non-error return from setjmp()\n");
doing_stuff();
break;
}
printf("<<-- manage_setjmp()\n");
}
int main(void)
{
printf("-->> main()\n");
manage_setjmp();
printf("<<-- main()\n");
return(0);
}