22

「ジャンプラベル」の配列を宣言したい。

次に、この配列の「ジャンプラベル」にジャンプします。

しかし、私はこれをどのように行うのか分かりません。

次のコードのようになります。

function()
{
    "gotolabel" s[3];
    s[0] = s0;
    s[1] = s1;
    s[2] = s2;

    s0:
    ....
    goto s[v];

    s1:
    ....
    goto s[v];

    s2:
    ....
    goto s[v];
}

誰かがこれを実行する方法を知っていますか?

4

11 に答える 11

44

「値としてのラベル」として知られるGCC機能で可能です。

void *s[3] = {&&s0, &&s1, &&s2};

if (n >= 0 && n <=2)
    goto *s[n];

s0:
...
s1:
...
s2:
...

GCC でのみ動作します。

于 2009-06-02T08:49:58.817 に答える
17

gotoコンパイル時のラベルが必要です。

この例から、ある種のステートマシンを実装しているようです。最も一般的には、それらはswitch-case構造として実装されます。

while (!finished) switch (state) {
  case s0:
  /* ... */
  state = newstate;
  break;

  /* ... */
}

より動的にする必要がある場合は、関数ポインターの配列を使用してください。

于 2009-06-02T08:41:23.827 に答える
12

Cでジャンプするコードアドレスを直接保存する方法はありません。スイッチを使用するのはどうですか。

#define jump(x)  do{ label=x; goto jump_target; }while(0)
int label=START;
jump_target:
switch(label)
{
    case START:
        /* ... */
    case LABEL_A:
        /* ... */
}

すべてのスタックレスパーサー/ステートマシンジェネレーターによって生成された同様のコードを見つけることができます。このようなコードは簡単に理解できないため、生成されたコードであるか、ステートマシンで問題を最も簡単に説明できる場合を除いて、これを行わないことをお勧めします。

于 2009-06-02T08:40:26.107 に答える
8

gotoの代わりに関数ポインタを使用できますか?

このようにして、適切な関数を呼び出して呼び出すための関数の配列を作成できます。

于 2009-06-02T08:40:51.643 に答える
6

単純な標準Cでは、これは私が知る限り不可能です。ただし、GCCコンパイラには、これを可能にする拡張機能があり、ここに記載されています。

&&拡張機能は、ラベルのアドレスを取得するための新しい演算子を導入します。この演算子は、gotoステートメントで使用できます。

于 2009-06-02T08:41:01.487 に答える
5

それがswitchステートメントの目的です。

switch (var)
{
case 0:
    /* ... */
    break;
case 1:
    /* ... */
    break;
default:
    /* ... */
    break;  /* not necessary here */
}

コンパイラによって必ずしもジャンプテーブルに変換されるとは限らないことに注意してください。

本当にジャンプテーブルを自分で作成したい場合は、関数ポインタ配列を使用できます。

于 2009-06-02T08:42:09.907 に答える
2

gotoでそれを行うことはできません。ラベルは、変数や定数ではなく、識別子である必要があります。ここでスイッチを使用したくない理由がわかりません。それが問題である場合は、同じように効率的である可能性があります。

于 2009-06-02T08:42:20.453 に答える
1

トークナイザー?これは、gperfが作成された目的のように見えます。いいえ、実際に見てください。

于 2009-06-07T10:00:04.037 に答える
1

簡単な答えとしては、コンパイラに本当にばかげたことを強制するのではなく、優れたプログラミング プラクティスを学ぶことです。

于 2009-06-02T08:47:22.190 に答える
1

最適化コンパイラ (GCC を含む) は、次の条件が満たされている場合、switch ステートメントをジャンプ テーブルにコンパイルします (構築しようとしているものとまったく同じ速度で switch ステートメントを作成します)。

switch ケース (状態番号) はゼロから始まります。

あなたのスイッチケースは厳密に増加しています。

switch ケースでは整数をスキップしません。

ジャンプ テーブルの方が実際に高速であるケースは十分にあります (switch ステートメントを処理するケースごとのチェック方法での数十回の比較アンド ゴトは、実際にはジャンプ テーブルよりも高速です)。

これには、コンパイラ拡張機能に依存する代わりに、標準 C でコードを記述できるという利点があります。GCC でも同様に高速に動作します。また、ほとんどの最適化コンパイラで同じように高速に動作します (Intel コンパイラがそれを行うことは知っていますが、Microsoft のものについてはわかりません)。また、速度は遅くなりますが、どのコンパイラでも動作します。

于 2016-04-16T18:25:18.427 に答える