cシミュレーションtry catch

2771 ワード

非ローカルジャンプ文---setjmpとlongjmp関数.非ローカルとは、通常のC言語gotoではなく、文が1つの関数内で実行されるジャンプではなく、スタック上でいくつかの呼び出しフレームをスキップし、現在の関数呼び出しパス上の関数に戻ることを意味します.include Int setjmp(jmp_buf  env);戻り値:直接呼び出すと0を返し、longjmpから呼び出すと0以外の値Void longjmp(jmp_buf env,int val)を返します.返される位置でsetjmpが呼び出されます.この位置はmain関数で、直接関数が呼び出されるため、返される値は0です.setjmpパラメータevnのタイプは特殊なタイプjmp_です.buf、このデータ型は、longjmpを呼び出すときにスタック状態を回復するために使用できるすべての情報を格納する何らかの形式の配列である.別の関数でenv変数を参照する必要があるため、仕様の処理方法はenv変数をグローバル変数として定義することです.エラーがチェックされると、longjmp関数が2つのパラメータで呼び出されます.1つ目はsetjmpを呼び出すときに使用されるenvで、2つ目のパラメータは0以外の値を持つvalで、setjmpから返される値になります.2番目のパラメータを使用する理由は、1つのsetjmpに対して複数のlongjmpを有することができるからである.簡単な例を見てみましょう#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>

void fun1(void);
void fun2(void);
 jmp_buf jmpbuffer;
void main(void)
{
    int i = 0;
    int j = 0;
    i = setjmp(jmpbuffer);
    if(i==0)
    {
        printf("first run/n");
        fun1();
        fun2();
    }
   else
   {
     switch(i)
     {
       
     case 1:
       printf("In fun1 /n");
     break;
   case 2:
     printf("In fun2/n");
     break;
   default:
     printf("unkown error/n");
     break;
     }
          exit(0);
   }
    return 1;


void fun1(void)
{
    char *s = "hello";
    char *s1 = "Hello";
    if(strcmp(s,s1)!=0)
    longjmp(jmpbuffer,1);
}

void fun2(void)
{
    char *s = "world";
    if(strcmp(s,"World")!=0)
    longjmp(jmpbuffer,2);
}

この関数の実行結果は次のとおりです.root@root:~/program/test_program$ ./jmp_test
first run
In fun1

longjmpを使用してsetjmpにジャンプすると、プログラムがアクティブに終了します!異常終了を投げ出すことに相当します!実はこの2つの関数はC++の中の異常関数をシミュレートすることができます:setjmpとlongjmpを使用して以下のいくつかの点に注意します:1、setjmpとlongjmpを組み合わせて使用する時、それらは厳格な前後の実行順序が必要で、つまり先にsetjmp関数を呼び出して、それからlongjmp関数を呼び出して、以前保存された“プログラムの実行点”に回復します.そうでなければ、setjmp呼び出しの前にlongjmp関数を実行すると、プログラムの実行フローが予測不可能になり、プログラムがクラッシュして終了しやすくなります.2、レジスタタイプの変数が常に変わらないと仮定しないでください.longjmpが呼び出された後、setjmpによって返される制御フローでは、プログラム内のレジスタタイプの変数は復元されません.レジスタタイプの変数とは、プログラムの実行効率を向上させるために、変数がメモリに保存されず、直接レジスタに保存されることを意味する.レジスタタイプの変数は一般に一時変数であり,C言語ではregisterによって定義されたり,アセンブリコードを直接埋め込んだりするプログラムである.このタイプの変数.longjmpはsetjmp呼び出しの後、longjmpはsetjmpの役割ドメイン内にある必要があります.具体的には、1つの関数でsetjmpを使用してグローバルラベルを初期化し、関数が返されない限り、longjmp呼び出しによってsetjmpの次の文にジャンプして実行できます.実際にsetjmp関数は呼び出し先のローカル環境をjmp_に保存します.bufの構成では、主調関数の対応するメモリが解放されていない限り(関数が返されるとローカルメモリが失効する)、longjmpが呼び出されると、保存されたjmp_bufパラメータに従ってsetjmpに復元された場所で実行することができる.
 
例:https://github.com/FredericGuo/CoffeeCatch.JNI