Question: In what ways could the function types be different, and still
be compatible? I'm guessing it's safe if the conversion adds const
and/or volatile qualifiers to some parameters. Could you replace a void*
parameter with a char* parameter? A signed integer with an unsigned
integer? What if the real function returns a value, but the pointer it's
called through is to a void function type?
Two *prototyped* function types are compatible (only) if corresponding
parameters are compatible ignoring top-level qualification and after
"adjustment" to pointer of (declared) array or function parameters,
and both or neither end with ellipsis (variadic). void* and char* are
not compatible according to the type rules, although they are required
to have the same representation and so substituting them will work in
practice unless the implementation is odd (or perverse) enough to pass
them differently, and the same for corresponding signed and unsigned
integers. Including plain/signed/unsigned char, and pointers thereto.
An incomplete or "forward declared" struct or union is compatible with
the completed type, and (nearly) identically declared such types or
enums in different t.u.s are compatible although formally they are not
the same type. An enum is compatible with an implementation-defined
integer type, usually int. Array of unspecified (or in C99 VLA) bound
is compatible (at compile time) with array of fixed bound. I think
that's all the freedom you officially have.
The more complicated cases are compatibility between or with
unprototyped function types, e.g.:
int foo (int x, double y);
int foo (x, y) short x; float y; { blah blah }
are compatible, and a pointer to unspecified-args function:
int (*ptr)() = foo;
can be silently converted from any function pointer, but can correctly
be used to call only a function with no arguments (and returning int).
For unprototyped definitions, the void*-char* and signed-unsigned
cases are permitted in 6.5.2.2, which is more detailed than 6.3.3.8.
Both prototyped and unprototyped declarations (and definitions) of a
function do define the return type, and (so) function types with
different return types are never compatible.
- David.Thompson1 at worldnet.att.net