2017-05-07 13 views
1

(再び)後藤を計算し、そしてIは、計算後藤のこの古い必要にぶつかっ(ALA fortran4 :))Iは、携帯ANSI-Cでこれをコーディングする必要C89私はオートマトンをコーディングする必要がどのように

longjmp/setjmpから離れて、埋め込まれたASM()から離れて、ansi-C拡張でない場所から遠ざかっていたいです。

誰でもこれを行う方法を知っていますか?

+0

まあ、いわゆる「計算された後藤は」Cのみで非ポータブル拡張機能として存在しているおそらく、あなたのを解決するための滑らかな印象の方法があります問題。何が問題ですか? – DeiDei

+0

ansi Cにはそのようなメカニズムはありません。あなたの状態表現を適切に設計し、そのアドレスを受け入れる関数ポインタを使用してください。 – StoryTeller

+0

また、ANSI準拠(C89)が必要な場合は、タイトルが誤解を招く可能性があります。 – StoryTeller

答えて

2

私はコメントで言ったように、goto以外のものを使用しないというあなたの嘆願にもかかわらず、標準Cは何も提供していません。

あなたの状態を適切に設計し、それに対するポインタをハンドラ関数に渡して変更します。こうすることで、ハンドラは次の関数呼び出しを設定できます。このような何か:

struct state; 
typedef void state_func(struct state*); 
#define NULL_ACTION_ADDRESS (state_func*)0 

struct state { 
    state_func *action; 
    int   value1; 
    int   value2; 
}; 

#define INIT_STATE { initial_action, -1, -1} 

state_func initial_action; 
state_func handle_a; 
state_func handle_b; 

int main(void) { 
    struct state s = INIT_STATE; 

    while(s.action != NULL_ACTION_ADDRESS) { 
     (*s.action)(&s); 
    } 

    return 0; 
} 

void initial_action(struct state* ps) { 
    ps->action = &handle_a; 
} 

void handle_a(struct state* ps) { 
    ps->action = &handle_b; 
} 

void handle_b(struct state* ps) { 
    ps->action = NULL_ACTION_ADDRESS; 
} 
2

私はそれを得たと思うが、私はこのトピックに関するすべてのさまざまなスレッドを見直し、一切のANSI Cソリューションは、まだ私は収まるこれを行うための方法を見つけていないところ私はそこにあることに同意し始めました私のニーズ。私がstackoverflowで見たすべての解決策は、ラベルのaddrを取得し、それをテーブルに埋め込み、次にこのテーブルとgotoにインデックスを付けるという考えに基づいています。これはgcc/clangのnon ansi拡張子またはasm拡張子です。

私はそれにもう一度try toniteを与えて、これを手に入れました。私はこの

#ifndef CGOTO_dcl 
#define CGOTO_dcl(N) int CGOTO_##N 
#define CGOTO_LE(l) l, 
#define CGOTO_LG(l) case l:goto l; 
#define CGOTO_def(N)            \ 
    if(0){typedef enum {N(CGOTO_LE)} N; CGOTO_##N: switch(CGOTO_##N)\ 
    {N(CGOTO_LG) default:CGOTO_##N=0;goto CGOTO_##N;}} 
#define CGOTO(N,i) CGOTO_##N=i; goto CGOTO_##N; 
#endif 

使用量は、この実装では、この

#include <stdio.h> 
#include "cgoto.h" 
int f(int x) 
{ //... 
    CGOTO_dcl(gtb); 
    //... 
# define gtb(L) L(l0) L(l1) L(l2) 
    CGOTO_def(gtb); 
    //... 

    CGOTO(gtb,x); 
    l0: printf("error\n"); 
    return(0); 

    //... 

    l1:return(11); 
    l2:return(22); 
    l3:return(33); 
} 

int main() 
{ printf("f(0)=%d f(1)=%d f(2)=%d,f(3)=%d\n",f(0),f(1),f(2),f(3)); 
} 

のようなものである必要がありcgoto.hインクルードファイルで

という名前の、ジャンプのコストは)(2つのジャンプやスイッチであり、それは逐次的であり、次に最適化可能である。したがって、これは関数呼び出しと比較して合理的に実行されますが、移植性を犠牲にして、ラベルソリューションよりも少し劣るパフォーマンスを示します(& &)。

この実装では、ラベルコード(セマンティックアクション)はswitch()に限定されず、共有セマンティックアクションを持つジャンプテーブルを実装できます。

索引はローカルのgoto_table_indexに割り当てられ、このリエントラント(マルチスレッド可能)を使用して関数を作成しますが、オプティマイザはこの一時割当てを完全に削除できます。

ジャンプテーブルの1番目のラベルは、インデックスの範囲外のインデックスをキャッチする意味で(この実装では)「特別」です。最初のラベルは「エラー」ラベルです。あなたのコードが弾丸である場合、つまり、範囲外のインデックスを取得する方法がない場合、1番目のラベルには特定の意味がありません。

CGOTO_dcl(gtb); 

ジャンプテーブル 'gtb'自身のインデックスを自動整数として宣言して再入可能にします。

# define gtb(L) L(l0) L(l1) L(l2) 
    CGOTO_def(gtb); 

GTBという名前のジャンプテーブルを定義し、ラベルは、入力/ L(ラベル)で除去ので、それはかなり便利で、ラベルが意味を持つ名前ですすなわち、これは、本質的に象徴的であることができます。 #defineをswitch()の場合、ラベルの追加/抑制は、多くの場合、#defineの番号を変更することが問題であることを意味します。

#defineはCGOTO_def()から切り離すことができますが、それらをまとめておく方が理にかなっています。しかし、CGOTO_def()は関数のローカル宣言の後に置かれなければなりません。これはコードであるswitch()を含んでいるからです。

uniqジャンプテーブルは、関数の複数の場所で使用できます。

CGOTO(gtb,x); 
... 
CGOTO(gtb,y); 

ラベルは、すべての複数のジャンプテーブルに

# define gtb1(L) L(l0) L(l1) L(l2) 
    CGOTO_def(gtb1); 
# define gtb2(L) L(l0) L(l4) L(l5) 
    CGOTO_def(gtb2); 

だから、すべてを入力することができ、この5月)は、ジャンプテーブルの定義2ラインの#defineとCGOTO_def(ただし、醜い、まだ管理可能で実用的で、半完成品であり、持ち運び可能です。

我々は戻っFTN4にある:)

乾杯、 ファイ

+0

これは深刻な恐ろしいスパゲッティコードです。 「計算されたgoto」を最初から始める必要性は、泥のようなプログラム設計から生じたものであり、この狂ったマクロ・メタ・プログラミングは、既存の問題に対する妥当な解決策ではありません。オリジナルの問題に対する実際の解決策は、ほぼ確実に元のプログラム設計を修正することです。 – Lundin

+0

されている...私たちはすべての良いプログラミングの練習を窓から投げたので...私はsetjmp/longjmp関数が悪化する方法を把握することはできません。 – Lundin

+0

これは正直なところ、非常に興味深い解決策です。 'case l:goto l'はコンパイラに十分な情報を与えて、単一のジャンプに最適化することさえできるかもしれません。 すべてのC "エリート"についてはごめんなさい。彼らは誰かがこのような質問をする理由を把握することはできません。私は100,000人以上の担当者が "あなたはヘッダーに関数を定義することはできません"と言ってくれました。 – ktb

関連する問題