1

longjmpを使用してgoto命令をシミュレートしたいのですが、構造体タイプ(int、float、bool、char)の要素を含む配列DSがあります。xがDS[TOP].int_valである「lablex」とラベル付けされた場所にジャンプしたいと思います。どうすればこれを処理できますか?

サンプルコード:

...
jmp_buf *bfj;
...
stringstream s;s<<"label"<<DS[TOP].int_val;
bfj = (jmp_buf *) s.str();
longjmp(*bfj,1);

しかし、問題があると思ったので、どうすればよいですか?

エラー:

output.cpp:関数内'int main()':

output.cpp:101:エラー:タイプ'std :: basic_string、std ::allocator>'からタイプ'__jmp_buf_tag(*)[1]'</p>への無効なキャスト

4

5 に答える 5

5

longjumpを使用する通常の方法は、ここで説明するようにsetjump()と組み合わせることです。通常、switch-caseまたは仮想関数で行われるようにジャンプテーブルを作成したいようです。

とにかく、コード(コンパイル時)のラベルは文字列(実行時)では到達できないので、それはすでにあなたの最初の問題です。あなたは本当にあなたがジャンプしたい場所のアドレスを見つける必要があるでしょう、そして私の最も良い推測はあなたのラベルがある場所にsetjump()を置くことでしょう。

于 2010-06-21T18:27:43.257 に答える
5

あなたはおそらくlongjmpをまったく使いたくないでしょうが、人々が「なぜあなたはそれをしたいのですか?」と質問に答えるとき、私はそれを嫌います。指摘されているように、longjmp()の使用法は間違っています。正しく使用する方法の簡単な例を次に示します。

#include <setjmp.h>

#include <iostream>

using namespace std;

jmp_buf jumpBuffer;  // Declared globally but could also be in a class.

void a(int count) {
  // . . .
  cout << "In a(" << count << ") before jump" << endl;
  // Calling longjmp() here is OK because it is above setjmp() on the call
  //   stack.
  longjmp(jumpBuffer, count);  // setjump() will return count
  // . . .
}


void b() {
  int count = 0;

  cout << "Setting jump point" << endl;
  if (setjmp(jumpBuffer) == 9) return;
  cout << "After jump point" << endl;

  a(count++);  // This will loop 10 times.
}


int main(int argc, char *argv[]) {
  b();

  // Note: You cannot call longjmp() here because it is below the setjmp() call
  //  on the call stack.

  return 0;
}

longjmp()の使用に関する問題は次のとおりです。

  1. setjmp()は呼び出さない
  2. スタック上または動的にjmp_bufを割り当てていません。 jmp_buf*bfjは単なるポインタです。
  3. char*jmp_buf*にキャストして、それが機能することを期待することはできません。C ++は動的言語ではなく、静的にコンパイルされます。

しかし、実際には、 longjmp()を使用する必要はほとんどありません。

于 2010-06-21T20:15:29.107 に答える
2

あなたはC++に完全に失敗しました。第一に、gotoは悪いものであり、初心者向けではありません。for、while、break、continueなどが存在する理由があります。次に、文字列を識別子に変換しようとしています。これは、自分でコーディングしない限り、実行時に不可能です。第三に、あなたは.. const char*をjmp_buf*にキャストしようとしていますか?何?

それに加えて、C++にはgotoがあります。しかし、intを指定してジャンプしたい場合は、それを切り替える必要があります。

switch (DS[TOP].int_val) {
case 1:
    goto label1;
    break;
case 2:
    goto label2;
    break;
default:
    throw std::runtime_error("Unrecognized label!");
}
于 2010-06-21T18:25:52.700 に答える
0

関数ポインタが必要なようです。


((void(*)(void))*((int *)DS[TOP].int_val))();

これはDS[TOP].int_valueをアドレスのように扱い、それにジャンプします。DS [TOP] .int_valueが配置されている場所にジャンプする場合は、次のようにします。


((void(*)(void))*((int *)&DS[TOP].int_val))();

いずれにせよ、醜い、醜いコード。しかし、それはあなたが望むことをするはずです。

于 2010-06-21T18:47:16.153 に答える
0

setjmp()が呼び出されると、システムは呼び出しとパラメータースタックのスナップショットを効果的に取得します。このスナップショットは、ユーザーコードがsetjmp()が呼び出されたブロックを終了するまで有効です。そのスナップショットでlongjmp()が呼び出されると、setjmp()が初めて戻ったかのように実行が再開されます。ただし、ゼロを返す代わりに、longjmp()に渡された2番目のパラメーターが返されます。無効なスナップショットを使用してlongjmp()を呼び出すと、非常に悪い影響を与える可能性があることに注意することが非常に重要です。一部のシステムでは、このような無効な呼び出しは機能しているように見えるかもしれませんが、後でクラッシュするような方法でシステムを破損します。

setjmp()/ longjmp()は純粋なCプログラムでは適切な場合がありますが、Cプログラムでsetjmp()を呼び出してスナップショットを作成し、次にlongjmp()を呼び出してそのスナップショットに戻るC++コードを呼び出すことは災害のレシピ。それを実行したいほとんどすべての状況は、例外を使用してより適切に処理される可能性があります。

于 2010-06-21T22:21:48.210 に答える