function pointer in C, with or without *? - c

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.

Related

Why is my function in a function being regarded as a pointer?

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*);

pointers to functions, with flexible types

I write a code with a connectivity list of a flexible type.
My database contains a list of nodes with data that might be a char* or a VERTEX* (struct defined by me). hence I defined the struct as with a field void*.
I also wish to have an operation which compares the strings in that field, so the list has a field defined:
DATA_EQ DataEqual
and defined a function which checks if the data of two nodes is equal:
typedef BOOL (*DATA_EQ) (void* pl, void* pr);
in order to define a DATA_EQ function for the list, in the case of string data, I created the following function in the .c file:
static BOOL stringDataEqual(char* pd1, char* pd2){
return ( strcmp(pd1, pd2) == 0 );
}
Finally, I want this function to be defined on my list, so I wrote:
pList->dataEqual = stringDataEqual;
but I guess the fact that I tried to specify the void* as char* is not good.
I haven't worked with pointers to functions in the past, so I might have done some silly mistakes...
I got the warning (after running gcc to complie):
warning: passing argument 1 of ‘ListCreate’ from incompatible pointer type [enabled by default]
I need my code to compile without any warnings, how do I solve/work around that?
Thanks ahead to anyone who helps,
Oded
Use casts to cast to and from void pointers. Your function becomes:
static BOOL stringDataEqual(void* pd1, void* pd2) {
return ( strcmp((char*)pd1, (char*)pd2) == 0 );
}
You can call this function by casting the parameters to void*.

Are these two pointer types really incompatible?

I have the following typedef and higher order function:
typedef void block_fn (struct block*, block_sector_t, void* buffer);
static void block_apply (struct page* page, block_fn *block_fn) {
int i = 0;
for (i = 0; i < PAGE_SECTORS; i++) {
block_fn(swap.device, page->sector * PAGE_SECTORS + i, page_kpage(page)
+ i * BLOCK_SECTOR_SIZE);
}
}
And I call it in the following two places:
block_apply (page, &block_write);
...
block_apply (page, &block_read);
block_read and block_write have the following signatures:
void block_read (struct block *, block_sector_t, void *);
void block_write (struct block *, block_sector_t, const void *);
This causes GCC to complain:
../../vm/swap.c:94:13: note: expected void (*)(struct block *, block_sector_t, void *) but argument is of type void (*)(struct block *, block_sector_t, const void *)
Is GCC right to be angry? Is it safe to pass this function pointer in this way?
EDIT: I understand that these two function pointers are of different types. My question is whether or not it is safe to use them in this way: can it trigger undefined behavior? Is there a case where passing a function pointer with an incompatible type in this way will cause something unexpected to happen?
yes, it's right to complain in general, though not meaningful in your case
by saying const void *, you are declaring that the function will not modify the
pointed-to data. By omitting const, you are saying that it might.
The function signature is a contract between the caller and the callee, that the compiler
enforces. The compiler prevents the code from advertising a stricter signature than it
implements (eg, advertising read-only arguments when it writes to them.)
In your case, though, you just want a pointer to a function with limited type checking.
You could declare the type as taking const void *, and override the const with a type cast
when you invoke it.
The two pointer types are incompatible.
IMO, it is not safe to pass this function pointer in this way.
Higher level code knows what type block_apply() can handle because of its function signature. To pass a different type to block_apply() necessitates 2 things: 1) higher level code defeating the signature (casting) and 2) higher level code knowing that it is OK to do so.
Better to not oblige the higher level code from casting and relieve it of the burden of knowing the inner workings of block_apply().
To avoid casts, code could create another function block_apply_const(). Then call block_apply(page, &block_read) and block_apply_const(&block_write) as needed.
typedef void block_fn_const (struct block*, block_sector_t, const void* buffer);
static void block_apply_const (struct page* page, block_fn_const *block_fn) {
// same code
}
But that duplicates code.
Alternatively, a wrapper function could perform the cast. This is better than littering higher level code with calls to block_apply() with casts. Since casting should be done with caution and these static functions know that it is OK to do the cast, code here can do it.
static void block_apply_const (struct page* page, block_fn_const *block_fn) {
block_apply(page, (block_fn) block_fn);
}

C: Why aren't &(void *) and void** compatible?

I'm receiving an incompatible pointer type error warning although my code functions properly. First of all, here's a simplified version of my code:
typedef struct {
int field1;
int field2;
} my_struct;
void some_function(void **data){
// do something with *data
}
int main(int argc, char *argv[]){
my_struct *ptr = malloc(sizeof(my_struct));
ptr->field1 = 5;
ptr->field2 = 17;
some_function(&ptr);
}
The my_struct type is one example, but I'm actually using multiple types, so some_func must accept void**, rather than my_struct**. Each time I call some_func in the manner above, I recieve the following warning, and yet my code functions properly.
warning: passing argument 1 of ‘my_func’ from incompatible pointer type
I'm unsure of why these types aren't compatible, and would like to remove the warning in some way. For answers, feel free to explain why this is happening and, if possible, how to remove the warning (cpp directive, maybe?). Thanks!
Use a void * parameter type.
void ** is not a generic pointer type. void * is.
void* means (effectively) "a pointer to an untyped region of memory".
void** means (effectively) "a pointer to a region of memory, which contains pointers to untyped regions of memory".
Notice how the block in the middle has a type -- an array of void*. You're passing in effectively an array of mystruct*, which is a different type. So your compiler warns you.
Similar issues occur in C++ when trying to convert Derived** to Base**; but it applies here in C as well. (void* operates like the "base class" of all pointer types) Consider a piece of code like this:
void does_things(void** outParameter)
{
*outParameter = malloc(42); // Looks fine; writing void* to void* :)
}
int main()
{
my_struct* x = /*...*/;
does_things(&myStruct); // Ut oh, tries to make x point to
// something that is *not* a my_struct
}

function prototype with void* parameter

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 *.

Resources