2

この質問は、特定の実装で void ポインターを使用することの妥当性に関するものです。

無限ループで構成される比較的単純なプログラムがあります。各ループで、プログラムは定数値の固定範囲を反復処理し、各値に対して関数を呼び出します。呼び出される特定の関数は、使用可能な 3 つの関数のいずれかであり、実行時に引数によって指定されます。無限ループが始まる前に、指定された引数に基づいて関数への関数ポインターを設定する条件ブロックがあります。このように、条件ロジックは、すべてのループのすべての反復ではなく、1 回だけ実行する必要があります。

これは私が実装したもので、うまく機能しますが、関数の呼び出しごとに状態を維持したいと考えています。私の提案は、状態を構造体に格納し、各値で関数を呼び出すときにその構造体を渡すことです。問題は、各関数がその状態の異なる値のセットを格納するために異なる構造体を必要とし、3 つの関数すべてのプロトタイプが (関数ポインターに関して) 互換性がなければならないことです。3 つの関数のプロトタイプで void ポインターを使用してこれを解決し、互換性のあるプロトタイプを維持しながら、各関数に異なる構造体を渡すことができるようにします。

質問は; 私の提案は void ポインターの適切な使用ですか、それとも実行時のダイナミズムが多すぎるので、アプローチを再考する必要がありますか?

注: 3 つの関数のそれぞれで静的変数を使用することはできません。構造体も無限ループで使用できる必要があるためです。これは、値の範囲が繰り返される前後に何らかの処理を行う必要があるためです。

4

5 に答える 5

5

呼び出しの型を正しく保つように注意している限り、これは、説明したことを達成するためのかなり C の慣用的な方法です。

于 2011-04-13T21:23:07.567 に答える
2

を使用することで、型の安全性をある程度高めることができますunion

typedef struct {
        int a;
        char *b;
} s1;
typedef struct {
        double d;
        int *e;
} s2;
typedef union {
        s1 s1;
        s2 s2;
} ocd;
typedef int (*daemon_function)(ocd *);

次に、すべての関数が型である可能性がありますが、 ordaemon_functionを介して異なる引数を取ります。私はそれを意味のない忙しい仕事の束と呼ぶ傾向があります. シンプルなものも同様に機能します。ocd.s1ocd2.s2void*

構造体の前にマジック ナンバーを含めることもできます。関数は、マジック ナンバーを見て、それが正しいものかどうかを確認することで、型の安全性をチェックできます。

#define MAGIC 0x4d475600L
typedef struct {
    long magic;
    /* ... */
} whatever;

その後:

int f(void *p) {
    whatever *w = (whatever *)p;
    if(w->magic != MAGIC) {
        /* complain and go boom! */
    }
    /* ... */
}

私は Motif プログラミング時代にずっとマジック ナンバー トリックを行っていましたvoid*。Motif/Xt/X11 開発では多くのポインターを渡します。

于 2011-04-13T22:00:32.187 に答える
1

void *は、C では非常に慣用的です。個人的にはよく使用しますが、使用するときは常に、安全のためにタグ付き構造体を使用する傾向があります。つまり、各構造体の先頭に一意の型 ID を付けて識別します。

于 2011-04-13T22:03:05.463 に答える
1

void ポインターは、c 型付けシステムに、その仕事をやめて、混乱しないように信頼するように伝える方法です。これは void * の適切な使用法です。唯一の問題は、コンパイラが実行する型チェックにアクセスできなくなることです。非常に奇妙で診断が難しいバグを作成する可能性があります。自分が何をしているのかを理解している (自分のように聞こえる) と確信があり、コードのすべての行を数回チェックして、論理エラーがないと確信している場合は、問題ありません。

于 2011-04-13T22:08:50.053 に答える
0

通常は問題ありません。私はコンテキストを使用することを本当に好みvoid *ますが、それを避けたいようです。引数を解析して関数を選択するコードが既にいくつかあるため、スイッチで関数を選択し、反復ごとに明示的に呼び出すことができます。

于 2011-04-13T21:57:47.510 に答える