Is this code legal?
extern "C" typedef void (ft_blah_c)();
/*extern "C++"*/ typedef void (ft_blah_cpp)();
extern "C" void fn_blah_c() {}
/*extern "C++"*/ void fn_blah_cpp() {}
ft_blah_c *g_Blah_c = fn_blah_cpp; // <--- ?
ft_blah_cpp *g_Blah_cpp = fn_blah_c; // <--- ?
I have real code with similiar assigments, it compiles and executes without any problems (MSVC 2010).
No, this is not legal; conversion between function types cannot be implicit.
It is legal to explicitly cast between function types:
However actually calling a function through a function pointer of a different type is undefined behavior. You must convert back to the original type before calling the function.
The underlying reason for this, outside the scope of the standard, is that the machine instructions for calling a function can differ based on the function's language linkage. This is referred to as 'calling conventions' and involve many details such as argument and return value passing conventions, function prologue and epilogue, etc.
For example a function with C language linkage may expect to find its arguments on the stack while a function with C++ language linkage may expect arguments to be passed in registers. If calling code doesn't know the correct linkage it will place the argument data one place and the function will look in the other and only read garbage, thus failing to operate correctly.
In general that should not work. The problem is that when you call
fn_blah_c
orfn_blah_cpp
directly the compiler knows the function and the calling conventions to use, but if you store those in a function pointer the compiler only sees that pointer and can only use the type of the function pointer to determine how to pass the arguments and return types.If the calling convention for C and C++ are the same in your environment then it can work (and that is probably why your compiler is allowing it), but that is not the case in general and the assignment should fail.