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)-但我不喜欢这种方法,这对我来说似乎是多余的,而且 API 令人困惑。

  • 使用联合:

    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:为一个函数参数发送不同的结构,但这无关紧要,因为我想接受非指针参数。

处理此功能的正确方法是什么?

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需要知道(除了显而易见的 - 搜索键和数组长度)是数组中每个元素的大小,以便它可以计算数组中每个元素的地址并将其传递给比较函数。


如果您有一个要操作的类型的有限列表,那么拥有一系列findX()函数并没有错。上述方法需要将每种数据类型的函数传递给bsearch函数,但主要区别之一是不需要重复通用功能,通用函数可用于任何数据类型。

我真的不会说有任何正确的方法可以做到这一点,这取决于您,并且实际上取决于您要解决的问题。

于 2012-09-16T04:32:26.720 回答
1

我不确定回答我自己的问题是否礼貌,但我想听听你的意见。

我尝试使用 va_list 解决这个问题。为什么这样?因为这样我只能写一个函数。请注意,我知道参数应该是什么类型。这样我可以做到这一点:

    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 回答