Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 有没有一种方法可以传递带有泛型参数的函数指针?_C_Function Pointers - Fatal编程技术网

C 有没有一种方法可以传递带有泛型参数的函数指针?

C 有没有一种方法可以传递带有泛型参数的函数指针?,c,function-pointers,C,Function Pointers,我正在实现一个通用的单链表,其中列表节点存储指向其数据的指针 typedef struct sll_node { void *data; struct sll_node *next; } sll_node; 为了实现一个处理任何类型数据的通用find子例程,我编写了它,以便它将指向比较函数的函数指针作为参数,如下所示: /* eq() must take 2 arguments. ex: strcmp(char *, char *) */ sll_node *sll_fi

我正在实现一个通用的单链表,其中列表节点存储指向其数据的指针

typedef struct sll_node
{   
    void *data;
    struct sll_node *next;
} sll_node;
为了实现一个处理任何类型数据的通用find子例程,我编写了它,以便它将指向比较函数的函数指针作为参数,如下所示:

/* eq() must take 2 arguments. ex: strcmp(char *, char *) */
sll_node *sll_find(void *data, int (*eq)(), sll_node *root);
您可以传递适用于当前数据类型的适当函数指针。。因此,如果在列表节点中存储字符串,则可以将strcmp作为eq()函数传递,依此类推。它起作用了,但我还是不满意

有没有一种方法可以在不放弃通用性的情况下明确指定比较函数参数的数量?

我一开始试过这个:

sll_node *sll_find(void *data, int (*eq)(void *, void *), sll_node *root);
我希望它能起作用。但是没有(编辑:它编译时带有警告,但我已经打开了-Werror!),我必须在strcmp周围编写一个包装函数,使其符合eq原型

然后我试着:

sll_node *sll_find(void *data, int (*eq)(a, b), sll_node *root);
或:


它们都不会编译,因为:“不带类型的参数列表只允许在函数定义中使用”

要使用
strcmp
,而不使用包装器或强制转换,声明需要

sll_node *findNode(void *data, int (*eq)(const char *, const char *), sll_node *root);
另一方面,如果将参数声明为
const void*
,则可以通过将
strcmp
强制转换为适当的类型来避免包装

方法1:直接投法,混乱但有效

    result = findNode( "hello", (int(*)(const void *, const void *))strcmp, root );
方法2:键入定义比较函数,然后使用它进行强制转换

typedef int (*cmpfunc)(const void *, const void *);
result = findNode( "world", (cmpfunc)strcmp, root );

编辑:在阅读了@WilburVandrsmith链接后,我决定保留这个答案。我将由读者决定提议的强制转换是否违反规范中的以下段落:

如果使用转换的指针调用类型不为的函数 与指向的类型兼容,行为未定义


兼容或不兼容,这是您决定的问题。

您上次尝试的解决方案最接近于正确。定义的类型函数指针中的参数需要使用其数据类型进行声明,就像使用常规函数声明一样,如下所示:

typedef int (*equality_fn)(char *a, char *b);
sll_node *sll_find(void *data, equality_fn eq, sll_node *root);
更新

要使其更通用,请使用void指针,然后将传递的void指针类型转换为
相等的匹配函数定义中所需的数据类型。\fn

typedef int (*equality_fn)(void *a, void *b);
sll_node *sll_find(void *data, equality_fn eq, sll_node *root);
要记住的另一件重要事情是,指针是指针是指针,而不管它指向什么或它最初是如何定义的。所以,您可以有一些函数指针,或者一个空指针,或者一个指向字节、字符、int的指针——任何东西——只要您在代码中正确地处理它,并在尝试使用它之前将它转换回有效的类型


在C语言中,大多数程序员没有充分利用的另一点是,函数名本身实际上只是在运行时调用的地址,因此它们也是指针

我解决这个难题的办法是(顺便说一句,避免指针typedef):

然后将所有比较器的类型设置为
相等\u fn
。如果你真的需要一个函数,那么就这样吧:

equality_fn eq_strcmp;  // a prototype

// ...

int eq_strcmp(const void *a, const void *b) { return strcmp(a, b); }

获得大量类型安全性,以换取潜在的PicoScope运行时惩罚-您希望使用哪种类型取决于您的应用程序。

比较函数通常使用
const
关键字声明,例如
int(*eq)(const void*,const void*)
。这是否解决了strcmp的问题?转换指针类型需要一个参数;在您的情况下,也许可以尝试循环直到NULL?@user3386109您对const关键字的看法是正确的(从惯用的角度来看),但它仍然给出相同的警告:警告:不兼容的指针类型将int(const char,const char*)传递给int()(void*,void*)类型的参数[-Wincompatible指针类型](我编辑问题以澄清)@concacid我在等待您的答复时尝试了代码。为了在没有包装的情况下使用
strcmp
,您需要精确匹配
strcmp
,这意味着使用
const char*
作为参数。您也可以强制转换
strcmp
。如果可行,我会尝试并将其添加到下面的答案中。@concacid Casting
strcmp
到合适的类型可以工作。我已经将其添加到我的答案中。好吧,但它不再是通用的了!@concacid我用其他信息更新了我的答案。:)实际上有一些平台(例如哈佛体系结构设备),其中数据指针指向数据,函数指针指向函数,两人永远不会相遇。在这样的平台上,向void*或从void*转换函数指针实际上是一个错误。谢天谢地,像英特尔和ARM这样的流行平台并不在其中。尽管强制转换函数指针通常会起作用,但不幸的是。@WilburVandrsmith说得不错。事实证明,
strcmp
可能无论如何都需要一个包装器,因为它返回0表示相等,这不是人们期望从
eq
函数得到的结果。我很快就会改变答案。非常感谢!这就是我一直在寻找的答案。我还在学习C语言,我不知道你可以像那样投射函数指针。我猜这仍然意味着调用方负责在将比较函数插入findNode()时强制转换比较函数,但这比包装函数或未指定的原型要好得多。作为一方,在看了之后,我仍然对进一步研究这个问题感兴趣,以了解哪些情况会导致未定义的行为。@concacid tl;dr:如果你使用的是原型,那么它必须完全匹配;如果您使用的是K&R风格的函数声明,那么会有一大堆奇怪的规则,基本上允许出现在K&R手册中的代码,而不允许其他任何代码。:)
typedef int equality_fn(const void *a, const void *b);

sll_node *sll_find(void *data, equality_fn *eq, sll_node *root);
equality_fn eq_strcmp;  // a prototype

// ...

int eq_strcmp(const void *a, const void *b) { return strcmp(a, b); }