Let's say I have the following C code:
/* 1 */ typedef void (*void_f) (void *);
/* 2 */ typedef void (*int_f) (int *);
/* 3 */
/* 4 */ void fun_v (void *priv) { }
/* 5 */ void fun_i (int *priv) { }
/* 6 */
/* 7 */ int main () {
/* 8 */ int *int_p;
/* 9 */ void *void_p;
/* 10 */ void_f vfun_p;
/* 11 */ int_f ifun_p;
/* 12 */
/* 13 */ int_p = void_p;
/* 14 */ void_p = int_p;
/* 15 */ vfun_p = fun_i;
/* 16 */ ifun_p = fun_v;
/* 17 */ }
When I compile, I get the following warnings:
15: warning: assignment to ‘void_f’ {aka ‘void (*)(void *)’} from incompatible pointer type ‘void (*)(int *)’ [-Wincompatible-pointer-types]
16: warning: assignment to int_f {aka ‘void (*)(int *)’} from incompatible pointer type ‘void (*)(void *)’ [-Wincompatible-pointer-types]
Note that there are no warnings about lines 13 and 14, although they are assignments of different pointers types. I understand that line 14 should be perfectly valid, since we are assigning a pointer to a "more general type", and maybe 13 could also be considered perfectly valid.
Now, it seems logical to consider void_f also a more general, compatible, type of function than int_f, and there are many valid situations in which an assignment of this type is needed (for example, providing a callback with a private opaque context, although this situation is the inverse).
How can I securely assign compatible non-equal function types without getting a warning?
I don't want to compile with -Wno-incompatible-pointer-types because I still want to be warned when I assign functions which clearly are not compatible, and I also don't want to write a cast like
/* 15 */ vfun_p = (void (*)(void *))fun_i;
/* 16 */ ifun_p = (void (*)(int *))fun_v;
because then any mistake in the assignment will be silently shadowed, even with types that clearly are not compatible.
The only option I find is to perform a cast of the argument inside the function:
void fun_i (void *priv) {
int *num;
num = (int *)priv;
/* Rest of code here */
}
But I also don't like this because it has a misleading signature, and I need to add a comment that the void * parameter is in fact an int * parameter.
Any compiler extensions to achieve it?
Any better idea about how to handle this situation?