C 使用函数指针作为方法参数
我试图使用函数指针来提高代码的效率。然而,我对这个概念还不熟悉,在将它用作另一个函数中的参数时遇到了麻烦C 使用函数指针作为方法参数,c,function-pointers,C,Function Pointers,我试图使用函数指针来提高代码的效率。然而,我对这个概念还不熟悉,在将它用作另一个函数中的参数时遇到了麻烦 void print(node_t *node, void *param) { FILE *f = param; // no cast needed ... 这会产生一个错误“从不兼容的指针类型初始化”。 有人能告诉我我做错了什么以及我应该做什么吗?当你这样做时: traverse(node, h, print(node, h)); 实际上,您正在尝试调用打印,而不是向
void print(node_t *node, void *param)
{
FILE *f = param; // no cast needed
...
这会产生一个错误“从不兼容的指针类型初始化”。
有人能告诉我我做错了什么以及我应该做什么吗?当你这样做时:
traverse(node, h, print(node, h));
实际上,您正在尝试调用打印,而不是向它传递指针。因此,您要传递给travel
的实际上是print
的返回值,而不是指向它的指针
正确的调用如下所示:
traverse(node, h, print);
然后在遍历
的内部调用回调:
void traverse(node_t *node, void *param, func_t func)
{
...
func(node,param);
...
}
然而,仍然存在一个问题。函数print
的类型与函数指针func\u t
不兼容。前者将FILE*
作为其第一个参数,而后者将void*
作为其第二个参数。与void*
之间的隐式转换仅在它是转换的源或目标时有效。它不适用于函数参数
假设您需要回调来处理各种不同的类型,您可以将print
函数更改为接受void*
并转换函数内部的参数
void print(node_t *node, void *param)
{
FILE *f = param; // no cast needed
...
首先:仅仅因为可以使用
void*
代替任何其他对象指针,这并不意味着指向接受void*
的函数的函数指针与接受文件*
的另一个函数兼容
因此,您必须更改函数指针类型以使用FILE*
,或者必须更改打印函数以使用void*
但是,编译器错误的原因是您在此处调用实际函数print
traverse(node,h,print(node,h))代码>,而不是将函数指针传递给它。由于此函数返回void
,编译器会说“嘿,我不能将void参数传递给此函数,因为它需要函数指针”。只需将此更改为:
traverse(node, h, print);
然后遍历<代码>将通过传递的函数指针调用函数。
< p>对于它的价值,也许你使用的是错误的编程语言:)你想要写的东西是C++,它是:
traverse(node, [node,h]{ print(node, h); });
然后,traverse将是一个模板函数,因此您不必仅传递一种函数,而是可以传递任何函子(可调用对象,例如实现调用运算符的类):
为了完整性起见,以下是它在C++中的外观:
struct Node {
std::vector<Node> children;
std::string name;
};
template <typename Obs>
void ctraverse(const Node &node, F fun, int level = 0) {
fun(node, level);
++level;
for (auto &n : node.children) {
ctraverse(n, fun);
}
}
void test(const Node &node, std::ostream &out) {
traverse(node, [&](auto &node, int level) {
out << setw(level) << setfill(' ') << " " << node.name << '\n';
});
}
struct节点{
性病媒儿童;
std::字符串名;
};
模板
void ctraverse(常量节点和节点,F fun,int level=0){
乐趣(节点,级别);
++水平;
用于(自动编号:node.children(&n){
ctraverse(n,fun);
}
}
无效测试(常数节点和节点,标准::ostream和out){
遍历(节点,[&](自动&节点,整数级){
我不应该为print传递参数?这是如何工作的?print如何知道要使用哪些参数?将参数传递给在第三个参数中传递的函数是遍历
的任务。嘿,几乎相同的答案。对于FGITW,我给你一个+1:)谢谢你的回答。我照你说的做了,效果很好。不过,我只是在玩,我注意到这也是对的:func_t fun=(func_t)print;traverse(node,param,fun);为什么这也是正确的?@gazillionTickets假设您没有修改打印
,这是不对的。您通过不兼容的指针类型调用函数来调用。您刚刚得到了“幸运”它是有效的。所以基本上,虽然我的代码可以工作,但它容易受到bug的攻击?@gazillionTickets它可能会工作,而做一些不相关的事情可能会突然导致它不工作。谢谢你的回答。我照你说的做了,它工作了。但是,我只是在玩,我注意到这也是正确的:func_t fun=(func_t)print;traverse(node,param,fun);为什么这也是正确的?@gazillionTickets它不是“正确的”,它是未定义的行为。未定义行为的一种形式是:代码工作正常(这次)。
struct Node {
std::vector<Node> children;
std::string name;
};
template <typename Obs>
void ctraverse(const Node &node, F fun, int level = 0) {
fun(node, level);
++level;
for (auto &n : node.children) {
ctraverse(n, fun);
}
}
void test(const Node &node, std::ostream &out) {
traverse(node, [&](auto &node, int level) {
out << setw(level) << setfill(' ') << " " << node.name << '\n';
});
}