So I'm doing an assignment where we need to pass functions we've made ourselves into a library provided for us.
Tree * createBinTree(int (*comparePointer) (TreeDataTypePtr data1,
TreeDataTypePtr data2), void (*destroyPointer) (TreeDataTypePtr));
Is the code I've been provided.
My function pointer for the comparePointer is
int(*compStr)(void *, void *) = &compareName;
Compare is
int compareName(void * rest1, void * rest2);
But when I pass it through like so
Tree * myTree = createBinTree((compstr)(str1,str2),die(str1));
I only get an error on compstr which is "passing argument 1 of createBinTree makes pointer from integer without a cast" and "expected 'int (*)(void *, void *) but argument is of type int.
You need to pass the function, not call the function and pass the return value:
Tree* myTree = createBinTree( compstr , die );
But this is still not correct. The types of compstr and die must be compatible with the parameter types of the function createBinTree:
int(*compStr)( TreeDataTypePtr , TreeDataTypePtr ) = &compareName;
in which case, compareName must be a function of the same type. The same goes for die.
Note that only casting function pointers to the compatible type will cause undefined behavior when they are used to call the function. The original type of the function pointer must be compatible with the type used to call the function. This will cause undefined behavior:
int(*compStr)(void *, void *) = &compareName;
Tree* myTree = createBinTree( ( int(*)(TreeDataTypePtr,TreeDataTypePtr ) )compstr , die );
Related
I am learning about threading with C, and I'm a bit confused about the example given. They declared a function print_name with return value of void, but then it returns a string — how and why? The function print_name accepts one argument which is called name but it is a pointer of void; what does a variable of type void mean, and how can it accept a string?
main.c
#include <stdio.h> // I-O
#include <pthread.h> // threading
void *print_name(void *name)
{
puts(name);
return name;
}
int main(int argc, char const *argv[])
{
pthread_t thread_id;
pthread_create(&thread_id, NULL, print_name, "ha ones be eilat");
pthread_join(thread_id, NULL);
return 0;
}
To compile and run with gcc
$ cc main.c -o main -Wall -pthread && ./main
ha ones be eilat
The argument type and return type is not void but pointer to void.
In C both argument passing and returning a value with the return statement happen as if by assignment. void * is a generic pointer type and conversions to and from void * from and to other pointer types will happen implicitly, i.e. without a cast.
The character literal which is an array of char decays to char * and is implicitly converted to void * to match the prototype of pthread_create. The void * is implicitly converted to char * to match the prototype of puts.
print_name has prototype void * print_name(void *) so that a pointer to that function will match the type expected by pthread_create (The third parameter is void *(*start_routine) (void *).)
The declaration of pthread_create is
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg
);
The type void * is a 'universal pointer' that can point to any object type. (On many, but not all, machines, a void * can also hold a function pointer — however, that's tangential to this question.) In C, any object pointer can be converted to a void * and back to the original type without change. Using void * can be dangerous; it can be extremely useful (and thread creation can show both dangerousness and usefulness).
Contrary to the claim in the question, the function print_name() is defined to return a void * value as well as accept a void * argument. The pthread_create() function expects a (pointer to a) thread function that matches the signature:
void *thread_function(void *);
And that's what is passed to it. Since the function returns a void *, it is legitimate to return the pointer it was passed, though that is actually an unusual thing to do.
The return value from the thread function can be collected by passing an appropriate, non-NULL pointer to pthread_join(); the example does not demonstrate that.
void *result;
if (pthread_join(thread_id, &result) == 0)
printf("Result: <<%s>>\n", result);
This would, in the example, print Result: <<ha ones be eilat>> on a line. Many times, you'd convert the returned pointer to an explicit non-void pointer — e.g. char *str = result; — and then use that.
Note that there is nothing in C that would stop you calling:
int i = 0;
if (pthread_create(&thread_id, NULL, print_name, &i) != 0)
…thread creation failed…
The wrong type of data is passed, but that will be treated as OK by the compiler. At run-time, if you're (un)lucky, an empty line will be printed, but anything is possible (because of undefined behaviour) as you passed an int * to a function that requires a char * to work correctly. This inability to check types is a weakness of void *, but it is also a strength as it allows the pthread_create() function to pass a pointer to any type of data to a function. The onus is on the programmer to get the types right — the called function must expect to convert the void * parameter to a pointer to the type that was really passed. Also, the data passed via the pointer to the function needs to be stable — not changed if another thread is started. There is no guarantee about the order in which threads will read the data passed. Passing a pointer to a structure and changing the value in the structure between calls to pthread_create() is a no-no. Similarly with the return value. There are some additional wrinkles there. The data pointed at must be valid after the function exits, so it can't be a local variable.
i'm using an array of pointer (which are addresses of functions).
I'm parsing multiple types of data (char *, int, etc) to them.
To avoid any type error i'm using multiples void *.
That's why i'm confused because the compiler says that they are incompatible type (thus, it work when I compile it).
The array prototype is : void *(*arg_handler[4])(void *arg);
I'm using a function called list to save the different addresses and return the function address with the specific arguments:
void *list(int x, void *arg)
{
arg_handler[0] = &my_putstr;
arg_handler[1] = &my_put_printable;
arg_handler[2] = &my_put_nbr;
arg_handler[3] = &my_put_nbr;
return (arg_handler[x](arg));
}
I'm calling list from the main function through:
list(f_type(s[x + 1]), va_arg(args, void *));
but I can't figure out why I got this error:
warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
for :
arg_handler[0] = &my_putstr;
arg_handler[1] = &my_put_printable;
arg_handler[2] = &my_put_nbr;
arg_handler[3] = &my_put_nbr;
any Idea ?
As alk said the warnings were appearing because the 4 functions where not typed as void *. So instead of making an array for each type I converted the functions as void * as so :
arg_handler[0] = (void *)my_putstr;
arg_handler[1] = (void *)my_put_printable;
arg_handler[2] = (void *)my_put_nbr;
arg_handler[3] = (void *)my_put_nbr;
I have a function in an ADT:
Pgroup new_group(int size, void (*foo)(void *));
In my other class I have this function to send in:
void foo(Pstruc x);
x is a pointer to a struct. When I try to call new_group however, I receive an error "expected 'void (*)(void )' but argument is of type 'void ()(struct struc_ *)". This is how I've been calling it:
Pgroup group = new_group(num, &foo);
Any suggestions?
You can cast the argument to the correct type to get rid of the diagnostic:
Pgroup group = new_group(num, (void (*)(void *)) foo);
Note that this is not portable as C does not guarantee that the representation between different pointers is the same. The best would be to use types that match in their declarations.
You can rewrite your original function from void foo(Pstruc x); to void foo(void* x);.
Or convert its type: (void(*)(void*))foo.
I have a function int rt_task_start (RT_TASK *task, void(*task_func)(void *arg), void *arg)
where in second argument i am passing a function with argument.
When i only pass a function name at that time there is no problem.(as expected it's working). rt_task_start(&demo_task1, demo, 1);
But when i pass rt_task_start(&demo_task1, demo(&val), 1); it's giving me error error: invalid use of void expression. Variable val is defined before. int val = 0;
When i call with this rt_task_start(&demo_task1, demo(val), 1); this is showing error Warning passing argument 1 of 'demo' makes pointer from integer without a cast then error: invalid use of void expression.
int *val;
*val = 0;
rt_task_start(&demo_task1, demo(&val), 1); this is also giving me error.
I can't understand what should i pass, as a void pointer. It's giving me error. Any Idea Please!
void (*task_func)(void *arg);
The above statement defines task_func to be a pointer to a function which takes a pointer of type void * and returns no value.
Therefore, when you call your function rt_task_start, you should pass a pointer to a function as the second argument. Also, you should pass a pointer of type void * as the third argument, not an integer. A function name evaluates to a pointer to the function, so you can simply pass the function name as the argument value, or you can use the address-of operator & before the function name.
int arg = 4;
// both calls are equivalent
rt_task_start(&demo_task1, demo, &arg);
rt_task_start(&demo_task1, &demo, &arg);
I'm not sure how the code in (1) can possibly compile. But here is what you should be using:
int rt_task_start (RT_TASK *task, void(*task_func)(void *arg), void *arg);
int val = 1;
rt_task_start(&demo_task1, demo, &val);
You cannot pass the function pointer bound to a specific argument, that is something like a closure, which isn't available in C. You can, however, pass the function pointer and then separately pass the argument you want to apply (which is what the function signature suggests you should do). But you must pass that argument as a pointer, not a literal.
Surely you want:
int i=1;
rt_task_start(&demo_task1, demo, (void*) &i);
Just by matching the argument types, remember the second argument is just a function pointer, not a function call with its own argument, it's own argument is only used when you call it within rt_task_demo. If you then want to use the value '1' in function 'rt_task_demo' you would recast it like
int ii = *(int*) arg;
so I'm trying to pass a type double * to a function that accepts void ** as one of the parameters. This is the warning that I am getting.
incompatible pointer type passing 'double **' to parameter of type 'void **'
Here is a snippet of my code.
int main( void )
{
// Local Declaration
double *target;
// Statement
success = dequeue(queueIn, &target);
}
Here's the prototype declaration of the function.
int dequeue ( QUEUE *queue, void **dataOutPtr );
I thought that if I passed target as a two level pointer that it would work, but I guess I'm wrong. Can someone please explain to me how come i'm getting this warning?
Even though all other pointer types can be converted to and from void * without loss of information, the same is not true of void ** and other pointer-to-pointer types; if you dereference a void ** pointer, it needs to be pointing at a genuine void * object1.
In this case, presuming that dequeue() is returning a single pointer value by storing it through the provided pointer, to be formally correct you would need to do:
int main( void )
{
void *p;
double *target;
success = dequeue(queueIn, &p);
target = p;
When you write it like this, the conversion from void * to double * is explicit, which allows the compiler to do any magic that's necessary (even though in the overwhelmingly common case, there's no magic at all).
1. ...or a char *, unsigned char * or signed char * object, because there's a special rule for those.
In your prototype declaration , you said second argument as void** ,so you have to type cast double** to void**.
Instead of this line success = dequeue(queueIn, &target);.
Call like this success = dequeue(queueIn,(void**) &target);
int main( void )
{
// Local Declaration
double *target;
// Statement
success = dequeue(queueIn, (void**)&target);
}
Use it like this.