这段代码合法吗?
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; // <--- ?
我有类似任务的真实代码,它编译和执行没有任何问题(MSVC 2010)。
答案 0 :(得分:3)
一般来说,这应该不起作用。问题是,当您直接调用fn_blah_c
或fn_blah_cpp
时,编译器知道要使用的函数和调用约定,但如果将它们存储在函数指针中,则只编译器看到那个指针,只能使用函数指针的类型来确定如何传递参数和返回类型。
如果C和C ++的调用约定在你的环境中是相同的那么它可以工作(这可能是你的编译器允许它的原因),但一般情况并非如此,并且赋值应该失败。
答案 1 :(得分:2)
不,这不合法;函数类型之间的转换不能隐含。
在函数类型之间显式转换是合法的:
ft_blah_c *g_Blah_c = reinterpret_cast<ft_blah_c>(fn_blah_cpp);
ft_blah_cpp *g_Blah_cpp = reinterpret_cast<ft_blah_cpp>(fn_blah_c);
然而,通过不同类型的函数指针实际调用函数是未定义的行为。在调用函数之前,必须转换回原始类型。
除了标准范围之外,其根本原因在于调用函数的机器指令可能因函数的语言链接而不同。这被称为'calling conventions',涉及许多细节,例如参数和返回值传递约定,函数序言和结尾等。
例如,具有C语言链接的函数可能期望在堆栈上找到其参数,而具有C ++语言链接的函数可能期望参数在寄存器中传递。如果调用代码不知道正确的链接,它会将参数数据放在一个位置,而函数将在另一个位置查看并且只读取垃圾,从而无法正常运行。