未定義の動作を呼び出しているため、1 つのコンパイラがクラッシュし、別のコンパイラが動作しているように見えても問題ありません。どちらも正しい - それが未定義の動作の美しさです。
問題は、保存されたコンテキスト (つまり、コンテキストを設定するために呼び出された関数が返されないjmp_buf限り) が有効であるということです。setjmp()
C99 標準 (現在の標準ではなくなりましたが、この文言は大幅に変更された可能性は低いです) は次のように述べています。
§7.13.2.1longjmp関数
この関数は、対応する引数を使用したプログラムの同じ呼び出しで
longjmp、マクロの最新の呼び出しによって保存された環境を復元します。そのような呼び出しがなかった場合、またはマクロの呼び出しを含む関数が暫定的に実行を終了した場合208) 、またはマクロの呼び出しが可変的に変更された型を持つ識別子のスコープ内にあり、実行が終了した場合動作は未定義です。setjmpjmp_bufsetjmpsetjmp
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);
}