如何编写C函数接受任何类型的(一个)参数

时间:2012-09-16 04:18:54

标签: c types variadic any

我在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也很混乱。

  • 使用union:

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

    但是这样我强迫用户了解any_type union,并在调用find之前创建它。我想避免这种情况。

  • 使用可变参数函数:int find(void* list, ...)。我喜欢这种方法。但是,我担心没有对参数数量的限制。用户可以自由写int x = find(list, 1, 2.0, 'c'),但我不知道它应该是什么意思。

我也看到了这个问题的回答:C : send different structures for one function argument但它无关紧要,因为我想接受非指针参数。

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

2 个答案:

答案 0 :(得分:7)

您可以尝试实现类似于bsearch等通用函数的函数,它可以对任何数据类型的数组执行二进制搜索:

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

不是硬编码函数内不同数据类型的不同实现,而是将指针传递给将执行类型相关操作的函数,并且只知道底层实现。在您的情况下,这可能是某种遍历/迭代函数。

bsearch需要知道的另一件事(除了显而易见的 - 搜索键和数组长度)是数组中每个元素的大小,因此它可以计算数组中每个元素的地址,将它传递给比较函数。


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

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

答案 1 :(得分: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

你怎么看?你认为这是比以前建议更好的解决方案吗?