2012-09-16 79 views
7

我正在C中实现简单的库列表,并且我在编写find函数时遇到了问题。如何写任何类型的接受(一个)参数的C函数

我想我的函数接受任何类型的参数来寻找,既: 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工会,以及find调用之前创建它。我想避免这种情况。

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

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

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

+0

没有一个。 – Mehrdad

+2

我会做的方法#1和利用新的C11'_Generic'的宏来区分类型。 – oldrinb

回答

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函数,但其​​中一个主要区别是不需要重复常用功能,并且通用函数可用于任何数据类型。

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

+0

看起来真的很简单(一见钟情)。现在我有有限的类型列表。但如果我想添加另一个类型,我需要编写另一个包装函数。我不认为这是如何解决这个问题的最好方法。 –

+0

@BartekChaber:是的,与C++和Java之类的语言中的模板不同,这并不是一种很好的方式来完成你想要的C语言。制作泛型函数并传递函数指针是我通常在项目中进行的。 – AusCBloke

+0

@AusCBloke:取决于你的要求,如果C11没问题,那就是_Generic。 – kyrias

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

您对此有何看法?你认为这是比以前建议的更好的解决方案吗?

+1

我肯定会用va_list方法。我不确定宏是否增加了很多。最可能的问题是,当列表是双打时,有人会“查找(列出,12)”。在这种情况下宏仍然没有给出警告。为什么有人会试图做'find(list,1,2.0,'c')'? – asc99c

+0

@ asc99c为什么?因为函数的签名允许这样:) 在搜索时,你绝对没有键入安全。我希望这是这种方法的唯一缺点。 –

相关问题