Reputation:
I am trying to use a function pointer to make my code more efficient. However, I am new to this concept and am having trouble using it as a parameter inside another function.
this gives an error "initialization from incompatible pointer type". Can someone tell me what I am doing wrong and what I should do instead?
Upvotes: 2
Views: 155
Reputation: 98435
For what it's worth, perhaps you're using the wrong programming language :) What you intended to write is pretty much C++, where it'd be:
traverse(node, [node,h]{ print(node, h); });
Then, traverse would be a template function, so that you're not constrained to passing just one kind of a function, but instead could pass any functor (a callable object, e.g. a class implementing the call operator):
template <typename Fun> void traverse(node_t *, Fun &&f);
But you've used a function pointer, since it's C, and a function pointer is not like the C++ closure: it can carry no parameters. Thus, passing the parameters is on you. I imagine that the FILE*
argument really comes from the node? Is that a directory tree you're trying to represent?
typedef struct {
node_t **children; // null-terminated array of child node pointers
const char *name;
} node_t;
typedef void (*cnode_observer_t)(const node_t *, int level, void *);
void ctraverse_level(const node_t *node, int level, void *extra,
cnode_observer_t cobserver)
{
cobserver(node, extra);
node_t **child = node->children;
++level;
while (*child) {
ctraverse_level(*child++, level, extra, cobserver);
}
}
void ctraverse(const node_t *node, void *extra, cnode_observer_t cobserver) {
ctraverse_level(node, 0, extra, cobserver);
}
void node_printer(const node_t *node, int level, void *file) {
assert(node && file);
FILE *f = file;
fprintf(f, "%*c%s\n", level, ' ', node->name);
}
void test(const node_t *node, FILE *file) {
ctraverse(node, file, node_printer);
}
For completeness' sake, here's how it'd look in 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';
});
}
Upvotes: 0
Reputation: 213960
First of all: just because a void*
can be used in place of any other object pointer, that does not mean that a function pointer to a function accepting a void*
is compatible with another function accepting a FILE*
.
So you either have to change your function pointer type to work with FILE*
, or you have to change the print function to work with void*
.
The reason for the compiler error is however that you call the actual function print
here traverse(node, h, print(node, h));
, rather than passing on the function pointer to it. Since this function returns void
, the compiler says "hey I can't pass a void parameter to this function expecting a function pointer". Simply change this to:
traverse(node, h, print);
and then traverse
will call the function through the passed function pointer.
Upvotes: 1
Reputation: 224082
When you do this:
traverse(node, h, print(node, h));
You're actually attempting to call print instead of passing a pointer to it. So what you're passng to traverse
is actually the return value of print
instead of a pointer to it.
The proper call would look like this:
traverse(node, h, print);
Then inside of traverse
you would call the callback:
void traverse(node_t *node, void *param, func_t func)
{
...
func(node,param);
...
}
There's still a problem however. The type of the function print
is not compatible with the function pointer func_t
. The former takes a FILE *
as its first parameter while the latter takes a void *
for its second parameter. The implicit conversion to/from a void *
only works when it is the source or destination of the conversion. It does not apply to function parameters.
Assuming you need the callback to handle various different types, you can change the print
function to accept a void *
and convert the parameter inside of the function.
void print(node_t *node, void *param)
{
FILE *f = param; // no cast needed
...
Upvotes: 4