Ok, I have checked the c99 standard and can say that this is undefined behaviour.
TL;DR: It is ok to cast/convert one function pointer to another type, but if you call that function, the function types must be compatible, otherwise, you get undefined behaviour. You don't get a warning because in each step you are converting between compatible function types, but in the end, helpMe
isn't compatible with pFunc
.
First of all:
char *helpMe(){
return "this is from helpMe";
}
Is valid and in C99 is the same as:
char *helpMe(void){
return "this is from helpMe";
}
From §6.7.5.3 (emphasis mine):
An identifier list declares only the identifiers of the parameters of
the function. An empty list in a function declarator that is part of a
definition of that function specifies that the function has no
parameters. The empty list in a function declarator that is not part
of a definition of that function specifies that no information about the
number or types of the parameters is supplied.
I don't know how this behaves in C89, I think that maybe, in C89 that is valid.
On the other hand, we have:
char * (*fNewFunc)() = helpMe;
This cast is valid, because you can cast a function pointer to a function of another type and go back without problem. The compiler won't throw a warning because even their types are compatible! (void against unespecified).
Section §6.3.2.3, paragraph 8 reads (again, emphasis mine):
A pointer to a function of one type may be converted to a pointer to a
function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to call
a function whose type is not compatible with the pointed-to type, the
behavior is undefined.
So, when you pass the pointer to hearThis
it is casted again, from char *(*)();
to char *(*)(char *);
which, again, they are compatible for the compiler (thus, not throwing a warning).
BUT the standard says if the function type you are calling is incompatible with the function type pointed to, then, the behaviour is undefined.
Te question now is, are they compatible?
The answer is NO. if you change the type of fNewFunc()
to char *(*fNewFunc)(void);
you will get a warning:
p.c: In function ‘main’:
p.c:12:5: warning: passing argument 1 of ‘hearThis’ from incompatible pointer type [enabled by default]
p.c:6:6: note: expected ‘char * (*)(char *)’ but argument is of type ‘char * (*)(void)’
In the standard there also says when two functions types are compatible. It is in §6.7.5.3.15. It's a bit more complicated than this :P
Why does it work?
Probably it works because the computer doesn't care. It just pushes or passes the parameters as registers, and helpMe
just ignores them. But you should know that it is undefined behaviour.