I have a function that returns a value. Is it safe to cast it to a function pointer type that returns nothing (void
) and then call it? Does the C standard give enough guarantees to make this safe on any platform, and equivalent to calling the function normally while ignoring the return value?
Bonus question: Is there a standards compliant calling convention that is used in practice on some platform and with which this is not safe to do?
Example code:
#include <stdio.h>
// simple function with a a side-effect;
// it is useful to call even when ignoring the return value
int f(int x) {
return printf("%d\n", x);
}
typedef void (*fun_t)(int);
int main() {
fun_t g = &f; // cast to void return type, issues a warning
g(123); // <-- is this safe, and equivalent to calling f(123) instead?
return 0;
}
Notes:
- This question is concerned only with changing the return type during the cast, not changing the types of any function parameters.
- I know that this is safe on the x86 and x64 platforms I use, assuming the default calling convention, but I would like to know if it is safe in general.
- I know that it is easy to work around this when necessary by writing a wrapper
void fw(int x) { f(x); }
. However, I would still like to know if doing this is safe so that I can better understand the fundamentals of the C language.
CodePudding user response:
No. This call invokes Undefined Behavior. See https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p8
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 referenced type, the behavior is undefined.
At link https://port70.net/~nsz/c/c11/n1570.html#6.7.6.3p15 one can find rules of compatibility of function types:
For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. ...
CodePudding user response:
No.
In addition to tstanisl's answer:
Consider a big return value as for example this structure:
struct big_t {
long la[1000000];
};
It is allowed as a return type.
Some compilers, including GCC for x86/x64, provide the space for the return value at the caller's site and call the function with a pointer to this space. In your use case, this pointer is not set.
So it is not safe on x86 or x64, nor any other architecture.
Have a lot of fun debugging the crashes!