Osa*_*afa 6 c function-pointers
我正在实现一个通用的单链表,其中列表节点存储指向其数据的指针.
typedef struct sll_node
{
void *data;
struct sll_node *next;
} sll_node;
Run Code Online (Sandbox Code Playgroud)
为了实现一个适用于任何类型数据的通用查找子例程,我编写了它,以便它将一个函数指针作为参数作为参数,如下所示:
/* eq() must take 2 arguments. ex: strcmp(char *, char *) */
sll_node *sll_find(void *data, int (*eq)(), sll_node *root);
Run Code Online (Sandbox Code Playgroud)
您可以传递适用于手头数据类型的函数指针.因此,如果在列表节点中存储字符串,则可以将strcmp作为eq()函数传递,依此类推.它有效,但我仍然不满意..
有没有办法明确指定比较函数参数的数量而不放弃它的一般性?
我一开始尝试了这个:
sll_node *sll_find(void *data, int (*eq)(void *, void *), sll_node *root);
Run Code Online (Sandbox Code Playgroud)
我希望它能起作用.但是没有(编辑:它编译了一个警告,但我有 - 错误!),我不得不围绕strcmp编写一个包装函数,使其符合eq原型.
然后我尝试了:
sll_node *sll_find(void *data, int (*eq)(a, b), sll_node *root);
Run Code Online (Sandbox Code Playgroud)
要么:
typedef int (*equality_fn)(a, b);
sll_node *sll_find(void *data, equality_fn eq, sll_node *root);
Run Code Online (Sandbox Code Playgroud)
这两个都不会编译,因为:"只有函数定义才允许没有类型的参数列表"
要在没有包装器或强制转换的情况下使用strcmp,声明需要是
sll_node *findNode(void *data, int (*eq)(const char *, const char *), sll_node *root);
Run Code Online (Sandbox Code Playgroud)
另一方面,如果将 args 声明为const void *,则可以通过强制转换strcmp为适当的类型来避免包装器。
方法一:直接施法,比较乱但是有效
result = findNode( "hello", (int(*)(const void *, const void *))strcmp, root );
Run Code Online (Sandbox Code Playgroud)
方法2:typedef比较函数,然后用它来强制转换
typedef int (*cmpfunc)(const void *, const void *);
result = findNode( "world", (cmpfunc)strcmp, root );
Run Code Online (Sandbox Code Playgroud)
编辑:读完@WilburVandrsmith 链接的这篇文章后,我决定保留这个答案。我让读者自行决定提议的演员阵容是否违反规范中的以下段落:
如果转换后的指针用于调用类型与指向的类型不兼容的函数,则行为未定义。
兼容还是不兼容,这是一个问题,你决定。