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.
This boils down to calling conventions. What if arguments are "sent" in reverse order for example? Or if there's a standard procedure that must be done after the function call that relies on the right number of arguments?
What you propose might work, but you shouldn't rely on this and the Standard attributes this as undefined behavior for a reason.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With