'Generic function typedef in C - how to get rid of initialization warning?
I'm experimenting with generic-like code and I have a function like this (a lot of not relevant code removed):
typedef uint8_t (*struct_converter_t)(void *, char *);
void convert_struct(
struct_converter_t converter, // this is a function
const char * file_name
){
some_struct_t * some_struct;
converter(some_struct, some_string_buffer);
}
And when I try to assign a function that takes some_struct_t
(not void *
):
static uint8_t some_converter(some_struct_t * vd, char * s);
to my struct_converter_t
like this:
struct_converter_t converter = some_converter; // WARNING HERE
I'm getting this:
initialization of 'struct_converter_t' {aka 'unsigned char (*)(void *, char *)'} from incompatible pointer type 'uint8_t (*)(some_struct_t *, char *)' {aka 'unsigned char (*)(struct <anonymous> *, char *)'} [-Wincompatible-pointer-types]
I'm not experienced in C and I would like to know if there is a way to get rid of this warning elegantly.
Solution 1:[1]
The function that you're assigning to the function pointer type has parameters that are incompatible with the function pointer.
Your function takes a some_struct_t *
as the first parameter but the function pointer type takes a void *
as the first parameter. While any object pointer can be converted to/from a void *
, that does not extend to function pointer parameters.
You need to change your function to take a void *
for its first parameter to be compatible with the function pointer. Then inside the function you can convert that void *
parameter to a some_struct_t *
.
Solution 2:[2]
In C, you can supply an argument of type X*
to a function expecting a void*
. But that's as far as the conversion goes. You cannot take a function whose first parameter is an X*
and use it as the argument for a parameter which is a function whose first parameter is a void*
.
The reason is that C does not guarantee that X*
and void*
have the same representation. It does guarantee that the compiler knows how to convert an X*
into a void*
in a way that does not destroy information, so that it can be later converted back to an X*
. But the void*
might look quite different.
So the compiler can insert code which changes the X*
to a void*
. But how does it change a char*(*)(X*)
(a function whose parameter is an X*
) to a char*(*)(void*)
? If the function is expecting that arg
has type char*(*)(void*)
, then it will mostly likely call arg(v)
where v
has type void*
. What then happens if arg
actually expects an X*
?
In order for the compiler to allow that possibility, it would have to somehow wrap arg
in what's usually called a trampoline; a function which accepts an X*
and converts it into a void*
in order to call a different function. That's not so easy -- for one thing, it would have to store the trampoline somewhere -- so C refuses to do it as an automatic conversion.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | dbush |
Solution 2 |