8

C でリスト用の単純なライブラリを実装していますが、find関数の記述に問題があります。

私の関数は、検索する任意のタイプの引数を 受け入れたいと思います:find(my_list, 3)find(my_list, my_int_var_to_find). 私はすでにリストの要素のタイプに関する情報を持っています

今のところ、これに対処する方法がいくつか見つかりました。

  • さまざまなタイプのサフィックスを持つさまざまな関数: int findi(void* list, int i), int findd(void* list, double d)- しかし、私はこのアプローチが好きではありません.

  • ユニオンを使用:

    typedef union {
       int i;
       double d;
       char c;
       ...
    } any_type;
    

    any_typeしかし、この方法では、ユーザーにユニオンについて知ってもらい、 find. それは避けたいと思います。

  • 可変引数関数を使用: int find(void* list, ...). 私はこのアプローチが好きです。ただ、引数の数に制限がないのが気になります。ユーザーは自由に書くことint x = find(list, 1, 2.0, 'c')ができますが、それが何を意味するのかはわかりません。

この質問への回答も見ました: C : 1 つの関数引数に対して異なる構造を送信しますが、非ポインター引数を受け入れたいため、無関係です。

この関数を処理する適切な方法は何ですか?

4

2 に答える 2

8

bsearch代わりに、任意のデータ型の配列でバイナリ検索を実行できる のような汎用関数に似た関数を実装してみることができます。

void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
              int (*compar)(const void *, const void *))

関数内のさまざまなデータ型のさまざまな実装をハードコーディングするのではなく、代わりに、型に依存する操作を実行する関数へのポインターを渡し、その関数のみが基になる実装を認識します。あなたの場合、それはある種のトラバーサル/反復関数である可能性があります。

bsearch配列内の各要素のアドレスを計算して比較関数に渡すことができるように、(明らかな検索キーと配列の長さは別として) 知っておく必要があるもう 1 つのことは、配列内の各要素のサイズです。


操作対象の型のリストが限られている場合、findX()関数のファミリを使用しても問題はありません。上記の方法では、関数に渡すデータ型ごとに関数が必要bsearchですが、主な違いの 1 つは、共通の機能を繰り返す必要がなく、ジェネリック関数を任意のデータ型に使用できることです。

これを行うための適切な方法があるとは言いません。それはあなた次第であり、解決しようとしている問題によって異なります。

于 2012-09-16T04:32:26.720 に答える
1

自分の質問に答えるのが礼儀正しいかどうかはわかりませんが、ご意見をお聞かせください。

va_list を使用してこの問題を解決しようとしました。なんでそうなの?この方法では、1 つの関数しか記述できないためです。引数の型を知っていることに注意してください。このようにして私はこれを行うことができます:

    int find(void* list, ...) {
      any_type object = {0};
      int i = -1;
      va_list args;
      va_start(args, list);
      switch(type_of_elem(list)) {
        case INT: object.i = va_arg(args, int); break;
        ...
      }
      /* now &object is pointer to memory ready for comparision
       * f.eg. using memcmp */
      return i;
    }

このソリューションの利点は、提示された switch-case をラップして、他の関数で再利用できることです。

引数の数に制限がないという私の懸念についてもう少し調査した後、printfこの制限がないことに気付きました。書くことができますprintf("%d", 1, 2, 3)。しかし、マクロを追加してソリューションを調整しました。

    #define find_(list, object) find((list), (object))

コンパイル時にエラーメッセージが生成され、find_ macro expects 2 arguments not 3.

あなたはそれについてどう思いますか?これは以前に提案されたよりも優れたソリューションだと思いますか?

于 2012-09-16T08:33:06.360 に答える