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

我正在为C中的列表实现简单的库,我在编写find函数时遇到了问题。

我希望我的函数接受任何类型的参数来查找, find(my_list, 3) :my 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之前创建它。 我想避免这种情况。

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

我也看到了这个问题的答案: C:为一个函数参数发送不同的结构,但它无关紧要,因为我想接受非指针参数。

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

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

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

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

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

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

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

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

我尝试使用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并将其重用于其他function。

在研究了一些关于对参数数量没有限制的关注后,我意识到printf没有这个限制。 你可以写printf("%d", 1, 2, 3) 。 但我用额外的宏调整了我的解决方案:

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

这会在编译时产生错误消息,说find_ macro expects 2 arguments not 3

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

Interesting Posts