I have a generic set of elements provided as a library.
/** Type for defining the set */
typedef struct Set_t *Set;
/** Element data type for set container */
typedef void* SetElement;
/** Type of function for copying an element of the set */
typedef SetElement(*copySetElements)(SetElement);
To create the set I must provide a pointer to a function that handles the copying of elements that I intend to use the set for.
Set setCreate(copySetElements copyElement);
I wrote the following type and copy function:
typedef struct location_t {
char *name;
} *Location;
Location locationCopy(Location location){
Location new_location = locationCreate(location->name);
return new_location;
}
*Obviously I simplified everything to focus the discussion.
When I call:
Set locations = setCreate(locationCopy);
I get a compiler errors:
warning: passing argument 1 of ‘setCreate’ from incompatible pointer type
expected ‘copySetElements’ but argument is of type ‘struct location_t * (*)(struct location_t *)’
Your example can be boiled down to
In the C standard pointers to functions are less versatile than pointer to objects.
You can convert a pointer to an object to a pointer to
void
(and back) without any cast (and warnings) because there is clause in the standard that explicitly allows for itNote here that a function is not an object.
Regarding pointers to functions the only thing that the standard guarantees is:
Later the standard clarifies what does it mean for two functions to be compatible:
Now you may think that
void*
andstruct location_t*
are compatible types, after all you can assign each others.But the standard is crystal clear:
It later goes on with extending this relationship for more complex types and qualified types.
It may sound surprising but
int*
andvoid*
are not compatible.They can be assigned but are not compatible, after all the
void*
could point to afloat
or an object with different alignment requirements.When it comes to pointers of different types the standard is concerned mostly about assigning them back and forth.
It doesn't forbid converting between incompatible pointer types, but using them is undefined behavior, hence the warning.
The better approach is to perform the cast inside the function, as suggested in this answer.
All your function should have signature
void* (void*)
so that no cast between pointers to functions is needed.The casts inside the functions are again subject to undefined behavior if the
SetElement
pointers are cast to incompatible pointers but that shouldn't happen if you'll calllocationCopy
only with pointers toLocation
s (as you indeed expect to do).As a side note, some programmer may frown upon using a
typedef
to hide a pointer type.