As far as I know, casting between incompatible function pointers, eg:
void aUnaryFunction(int a1)
{
/* .... */
}
void doSomethingWithFn()
{
typedef void(*BinaryFn)(int, const char*);
BinaryFn aBinaryFunction = (BinaryFn) &aUnaryFunction;
aBinaryFunction (3, "!!!");
}
should never be done, as is ‘undefined behaviour’ according to the C standard.
However I can’t see why, given the way function calls work in C, this example isn’t safe. All I’m doing is disregarding an argument.
Assuming that the treatment of an int first argument is consistent, all that will happen is that the const char* will be placed in a register when doSomethingWithFn() calls aBinaryFunction, aUnaryFunction will run as expected, and the const char* may be overwritten during aUnaryFunction, but that’s fine because nothing else will use it anyway.
Am I missing something here, or is this in fact safe?
(Or something in between the two, or both?)
The problem is that there isn’t a single “way function calls work in C” – there’s only the way that function calls work on a particular C implementation.
As a concrete example, “callee clean-up” calling conventions (like x86
stdcall) require the callee to know how many parameters were pushed on to the stack to perform the correct cleanup, which would be subverted in your example.