What is the difference between void (*xmlHashScanner)(void *payload, void *data, xmlChar *name) and void *xmlHashScanner(void *payload, void *data, xmlChar *name) in C?
Why do they behave differently?
xmlHashScanner is a user-defined function in the library libxml2.
When I try to redefine this function with a little different prototype: void *xmlHashScanner instead of void (*xmlHashScanner) I have the following error:
error: ‘xmlHashScanner’ redeclared as different kind of symbol
void *xmlHashScanner(void *payload, void *data, xmlChar *name)
^
In file included from /usr/include/libxml2/libxml/parser.h:18:0,
from /home/solar/Bureau/parser/src/diam_dict.c:12:
/usr/include/libxml2/libxml/hash.h:88:16: note: previous declaration of ‘xmlHashScanner’ was here
typedef void (*xmlHashScanner)(void *payload, void *data, xmlChar *name);
I wonder what is the difference between two of them.
void (*xmlHashScanner)(...) is a prototype for a function pointer returning nothing (void) whereas void *xmlHashScanner(...) is a prototype for a function returning a void*
void (*xmlHashScanner)(void *payload, void *data, xmlChar *name)
declares xmlHashScanner as a pointer to a function returning void, whereas
void *xmlHashScanner(void *payload, void *data, xmlChar *name)
declares xmlHashScanner as a function returning a pointer to void.
In both declaration and expression syntax, the unary * operator has lower precedence than the postfix [] subscript and () function call operators, so
T *a[N]; // a is an N-element array of pointer to T
T (*a)[N]; // a is a pointer to an N-element array of T
T *f(); // f is a function returning a pointer to T
T (*f)(); // f is a pointer to a function returning T
So you are comparing this:
void *xmlHashScanner(void *payload, void *data, xmlChar *name);
with this:
typedef void (*xmlHashScanner)(void *payload, void *data, xmlChar *name);
The first is a declaration for a function, and the second one is a typedef (defines a type). A function and a type are vastly different things; they are used for different purposes:
A function can be called
A type can be used for making a variable, which can then participate in calculations
This is what your compiler means by "a different kind of symbol" - there is no context (unless by accident) where these pieces of code can do anything similar. Consider, for example, tho pieces of code - 42 and &&. They have nothing in common - they are two different kinds of things.
To understand the details of the declaration, which are a bit confusing, use the right-left rule, which is also implemented here.
typedef void (*xmlHashScanner)(whatever) means xmlHashScanner type is a pointer to a function with whatever arguments returning void
void *xmlHashScanner(whatever) means xmlHashScanner is a function with whatever arguments, which returns void *
Related
I am a bit familiar with pointers and function pointers, perhaps, but this is confusing. I have a function and here is its, function header;
void report(List*, bool check(Item*, void*), void*);
The actual function is implemented same as the prototype in the header file. The prototype in main is: bool check(Item*, void*);. Basically this just reports things from a list, based on the return value of check. When calling the function in main.c, I use report(list, check(item, specificArg), arg); The only reason I am using void pointers, is because arg/specificArg could be whatever I want basically. But the problem is in check(item, specificArg), where the compiler reports:
incompatible integer to pointer conversion passing 'bool' to parameter of type 'bool (*)(Item *, void *)'
When doing check(item, specificArg) you're actually calling the function and passing its return value to the call to report, while it expected a function pointer instead.
The correct call syntax is:
report(list, check, arg);
The function prototype
void report(List*, bool check(Item*, void*), void*);
takes 3 arguments,
A List * which is unnamed
A pointer to a function that takes an Item * and a void * and returns a bool -- this parameter is named check
A void * which is also unnamed.
You are calling it with report(list, check(item, specificArg), arg) Notice the second parameter you are passing is a bool --> the result of the call to check(item, specificArg). Thus the mismatch.
this prototype is not correct:
void report(List*, bool check(Item*, void*), void*);
Suggest this prototype
void report( List*, bool, Item*, void*, void* );
then the signature would be:
void report( List* pMyList, Item* pmyItem, void* parm1, void* parm2 )
Then inside the report function:
bool mybool = check( pMyItem, parm1 );
However, if you want to pass different functions then suggest using the following prototype:
void report(List*, (bool (*)(Item*, void*)), void*);
I know that if I passed an argument like void (*func)(void *) to a variadic function, I can retrieve the argument like:
void (*func)(void *) = va_arg( args, void (*)(void) );
What if I pass something like void (** func)(void *)? What is the correct syntax to retrieve an argument of this type using va_arg?
Being frankly, your code is not standard-compliant. There is a tiny restriction for second argument of va_arg() macro:
... The parameter type shall be a type name specified such that the type
of a pointer to an object that has the specified type can be obtained
simply by postfixing a * to type. ...
According to this, notation like void (*)(void *) is unacceptable in this case. Since simple appending of * won't give you pointer to pointer to function. You may use only typedef-ed aliases:
typedef void (*func_ptr)(void *);
typedef void (**ptr_to_func_ptr)(void *);
func_ptr var1 = va_arg(ap, func_ptr);
ptr_to_func_ptr var2 = va_arg(ap, ptr_to_func_ptr);
Same as you've mentioned:
typedef void (** func_t)(void *);
func_t ppf;
va_list vl;
va_start(vl,n);
ppf = va_arg(vl, func_t);
...
To help pointer-to-function, I always use typedef as follows:
typedef void VoidFn(void *); // Function accepts void * and returns nothing.
That declares the prototype of the function as a typedef, allowing the use of the typedef elsewhere.
That way if you have this function:
void SomeFn(void *) {...}
you can declare this pointer:
VoidFn *fnPtr = &SomeFn; // A pointer to such a function.
This then makes it easier to change the prototype independently of the pointer, helping more... sophisticated constructs:
typedef void *VoidPtrFn(void *); // Function takes a void *, returning a void *
void *SomeOtherFn(void *) { ... }
VoidPtrFn *otherFnPtr = &SomeOtherFn;
VoidPtrFn **otherFnPtrPtr = &otherFnPtr;
I am implementing a generic singly linked list where list nodes store a pointer to their data.
typedef struct sll_node
{
void *data;
struct sll_node *next;
} sll_node;
To implement a generic find subroutine that works with any kind of data, I wrote it so that it takes as an argument a function pointer to the comparison function as follows:
/* eq() must take 2 arguments. ex: strcmp(char *, char *) */
sll_node *sll_find(void *data, int (*eq)(), sll_node *root);
You can pass the appropriate function pointer that works with the data type at hand.. So if you store strings in the list nodes, you can pass strcmp as the eq() function, and so on. It works but I'm still not satisfied..
Is there a way to explicitly specify the number of comparison function parameters without giving up its generality?
I tried this at first:
sll_node *sll_find(void *data, int (*eq)(void *, void *), sll_node *root);
I expected it to work. But no (edit: it compiles with a warning but I have -Werror on!), I had to write a wrapper function around strcmp to make it conform to the eq prototype.
I then tried:
sll_node *sll_find(void *data, int (*eq)(a, b), sll_node *root);
or:
typedef int (*equality_fn)(a, b);
sll_node *sll_find(void *data, equality_fn eq, sll_node *root);
which both wouldn't compile since: "a parameter list without types is only allowed in a function definition"
To use strcmp without a wrapper or a cast, the declaration needs to be
sll_node *findNode(void *data, int (*eq)(const char *, const char *), sll_node *root);
On the other hand, if you declare the args as const void *, then you can avoid the wrapper by casting strcmp to the appropriate type.
Method 1: direct cast, messy but effective
result = findNode( "hello", (int(*)(const void *, const void *))strcmp, root );
Method 2: typedef the comparison function, and then use it to cast
typedef int (*cmpfunc)(const void *, const void *);
result = findNode( "world", (cmpfunc)strcmp, root );
Edit: After reading this post that #WilburVandrsmith linked, I've decided to leave this answer as is. I leave it up to the reader to decide whether the proposed cast violates the following paragraph from the specification:
If a converted pointer is used to call a function whose type is not
compatible with the pointed-to type, the behavior is undefined.
Compatible or not compatible, that is the question, you decide.
Your last attempted solution is the closest to being correct. The parameters in your defined-type function pointer need to be declared with their data types, just like you would with a regular function declaration, like so:
typedef int (*equality_fn)(char *a, char *b);
sll_node *sll_find(void *data, equality_fn eq, sll_node *root);
UPDATE
To make it more generic use void pointers, and then type cast the passed void pointers to the needed data type in the matching function definition for equality_fn:
typedef int (*equality_fn)(void *a, void *b);
sll_node *sll_find(void *data, equality_fn eq, sll_node *root);
Something else important to remember is that a pointer is a pointer is a pointer, regardless of what it's pointing at or how it was originally defined. So, you can have some function pointer, or a void pointer, or a pointer to a byte, a char, an int--anything--as long as you handle it properly in your code and cast it back to a valid type before attempting to use it.
Something else that most coders don't take much advantage of in C is that function names themselves are really just addresses that are called at run-time, and so they are also pointers. ;)
My solution to this conundrum would be (avoiding pointer typedefs, incidentally):
typedef int equality_fn(const void *a, const void *b);
sll_node *sll_find(void *data, equality_fn *eq, sll_node *root);
Then make all your comparators be of type equality_fn. If you need to actually have a function then so be it:
equality_fn eq_strcmp; // a prototype
// ...
int eq_strcmp(const void *a, const void *b) { return strcmp(a, b); }
Gain lots of type safety in exchange for a potential picosocopic runtime penalty - which end of this trade you want to be on depends on your application.
I have two functions, each taking a pointer to a different type:
void processA(A *);
void processB(B *);
Is there a function pointer type that would be able to hold a pointer to either function without casting?
I tried to use
typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};
but it didn't work (compiler complains about incompatible pointer initialization).
Edit: Another part of code would iterate through the entries of Ps, without knowing the types. This code would be passing a char* as a parameter. Like this:
Ps[i](data_pointers[j]);
Edit: Thanks everyone. In the end, I will probably use something like this:
void processA(void*);
void processB(void*);
typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};
...
void processA(void *arg)
{
A *data = arg;
...
}
If you typedef void (*processor_t)(); then this will compile in C. This is because an empty argument list leaves the number and types of arguments to a function unspecified, so this typedef just defines a type which is "pointer to function returning void, taking an unspecified number of arguments of unspecified type."
Edit: Incidentally, you don't need the ampersands in front of the function names in the initializer list. In C, a function name in that context decays to a pointer to the function.
It works if you cast them
processor_t Ps[] = {(processor_t)processA, (processor_t)processB};
By the way, if your code is ridden with this type of things and switch's all over the place to figure out which function you need to call, you might want to take a look at object oriented programming. I personally don't like it much (especially C++...), but it does make a good job removing this kind of code with virtual inheritance.
This can be done without casts by using a union:
typedef struct A A;
typedef struct B B;
void processA(A *);
void processB(B *);
typedef union { void (*A)(A *); void (*B)(B *); } U;
U Ps[] = { {.A = processA}, {.B = processB} };
int main(void)
{
Ps[0].A(0); // 0 used for example; normally you would supply a pointer to an A.
Ps[1].B(0); // 0 used for example; normally you would supply a pointer to a B.
return 0;
}
You must call the function using the correct member name; this method only allows you to store one pointer or the other in each array element, not to perform weird function aliasing.
Another alternative is to use proxy functions that do have the type needed when calling with a parameter that is a pointer to char and that call the actual function with its proper type:
typedef struct A A;
typedef struct B B;
void processA(A *);
void processB(B *);
typedef void (*processor_t)();
void processAproxy(char *A) { processA(A); }
void processBproxy(char *B) { processB(B); }
processor_t Ps[] = { processAproxy, processBproxy };
int main(void)
{
char *a = (char *) address of some A object;
char *b = (char *) address of some B object;
Ps[0](a);
Ps[1](b);
return 0;
}
I used char * above since you stated you are using it, but I would generally prefer void *.
is there difference between with or without * for function pointer in C?
my function pointer declaration like this
typedef void (*DListVisitNode) (Node*, void*);
void DListTraverse( NodeList* , DListVisitNode , void*);
i have code like these
void print_index( Node* node, void* ctx)
{
printf("index:%d\n", node->index);
}
void* print_content( Node* node, void* ctx)
{
printf("content:%s\n", node->content);
}
void DListTraverse(NodeList* nodelist, DListVisitNode visit_func, void* ctx)
{
Node* cur_node = nodelist->headnode;
while( cur_node != NULL)
{
visit_func( cur_node, ctx );
cur_node = cur_node->nextnode;
}
}
DListTraverse( nodelist, print_content, NULL );
DListTraverse( nodelist, print_index, NULL );
both of DListTraverse works, but the one with * throws warning like this
warning: passing argument 2 of ‘DListTraverse’ from incompatible pointer type
i would simply delete the * afterward, but what's the difference between them?
print_content is defined as returning a void* i.e. a generic raw pointer.
print_index is defined as returning void i.e. without any results.
These are different signatures. Only print_index matches DListVisitNode.
My coding style is to define signature thru typedef like
typedef void signature_t (int);
Notice that no pointer is involved above. This names the signature of functions with one int argument and no results.
then, when needing pointers to such functions of above signature, use signature_t*
What is true is that the name of a function is like the name of an array; the language implicitly convert these to pointers. So DListTraverse(nodelist, print_content, NULL) is understood like DListTraverse(nodelist, &print_content, NULL)
You should enable all warnings on your compiler; with gcc that means giving -Wall -Wextra as program arguments to the compiler.
You've declared print_content as returning a void * (a pointer), which means it doesn't match DListVisitNode. However, as the function doesn't actually return anything (no return statement), you should be gatting another warning about that.
You may be confused about the difference between the following to typedefs:
typedef void (*DListVisitNode) (Node*, void*);
typedef void * (*DListVisitNode) (Node*, void*);
Or equivalently, between the following two types:
void (*) (Node *, void *)
void * (*) (Node *, void *)
The former is a pointer to a function returning void, the latter is a pointer to a function returning void *. Each of your print functions is an example of one such function.
Naturally, function pointers of different types are incompatible and not implicitly convertible, as surely this would make no sense: You can't just pretend that a function actually has a completely different signature and expect to be able to call it in any meaningful way. It would be like pretending that a bicycle is a car and then trying to refuel it at a gas station.
typedef void (*DListVisitNode) (Node*, void*);
Defines a pointer to an function as an type which takes two parameters Node * and void * and returns a void.
Once you use the above statement, DListVisitNode can be used as an type, the exact type is as mentioned above.
void* print_content( Node* node, void* ctx)
returns a void * and not a void.
C is a strongly typed language, the c standard mandates that any type violations must be reported by the compiler, hence there is a type mismatch and the compiler reports it to you. Basically, if your function doesn't return anything use the return type as void or if you intend to return a particular type then use that specific type as an return type.