The following code, I think, describes what I am trying to do. Specifically, I wish to cast a function pointer to a generic function type, with the only difference in signature being different pointer types.
Now, I'm aware that there is a requirement for function pointers to be compatible as discussed in this question, but I'm not sure whether having an argument of different pointer type satisfies that compatibility requirement.
The code compiles and runs, but, as expected, gives warnings about the assignment from incompatible pointer type. Is there some way to satisfy the compiler and achieve what I am after?
#include <stdio.h>
int float_function(float *array, int length)
{
int i;
for(i=0; i<length; i++){
printf("%f\n", array[i]);
}
}
int double_function(double *array, int length)
{
int i;
for(i=0; i<length; i++){
printf("%f\n", array[i]);
}
}
int main()
{
float a[5] = {0.0, 1.0, 2.0, 3.0, 4.0};
double b[5] = {0.0, 1.0, 2.0, 3.0, 4.0};
int (*generic_function)(void*, int) = NULL;
generic_function = &float_function;
generic_function(a, 5);
generic_function = &double_function;
generic_function(b, 5);
return 0;
}
The cleanest way is IMHO to perform the cast inside the function. This will force all the function signatures to be the same, and keeps the casts out of the caller's code. (this is for instance the way that qsort() wants it)
int double_function(void *p, unsigned size)
{
double *array = p
unsigned uu;
for(uu=0; uu < size; uu++){
printf("%f\n", array[uu]);
}
return 42;
}
Yes, declare it without a prototype.
int (*generic_function)() = NULL;
Now you can assign any function that returns int
, but also can pass any argument and the compiler is not required to reject incompatible arguments.
EDIT: As @Mat points out, to follow the C specification, you'd need to cast the function pointer back to the original type before calling it, which would make this whole excercise quite a bit less useful;
((int(*)(float*,int))generic_function)(a, 5);
Another solution (inspired by the answer from @wildplasser) is to wrap the functions in functions taking void* and performing a cast on that parameter instead. Doing it "by macro" is fairly simple;
#define WRAP(FN, TYPE) int FN##_wrapped(void* p, int len) { return FN((TYPE*)p, len); }
WRAP(float_function, float)
WRAP(double_function, double)
Then you can use the following rather clean lines instead;
generic_function = float_function_wrapped;
generic_function(a, 5);
That said, pointer casting isn't generally a solution I'd advocate, but it has its use cases.