3

这段代码合法吗?

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)。

4

2 回答 2

4

一般来说,这不应该工作。问题是,当您调用fn_blah_cfn_blah_cpp直接调用时,编译器知道要使用的函数和调用约定,但是如果将它们存储在函数指针中,编译器只能看到该指针,并且只能使用函数指针的类型来确定如何传递参数和返回类型。

如果 C 和 C++ 的调用约定在您的环境中是相同的,那么它可以工作(这可能是您的编译器允许它的原因),但通常情况并非如此,分配应该失败。

于 2012-12-29T11:52:58.147 回答
3

不,这是不合法的;函数类型之间的转换不能是隐式的。

在函数类型之间显式转换是合法的:

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);

然而,实际上通过不同类型的函数指针调用函数是未定义的行为。在调用函数之前,您必须转换回原始类型。

在标准范围之外,其根本原因是用于调用函数的机器指令可能因函数的语言链接而异。这被称为“调用约定”,涉及许多细节,例如参数和返回值传递约定、函数序言和结尾等。

例如,具有 C 语言链接的函数可能希望在堆栈上找到其参数,而具有 C++ 语言链接的函数可能希望在寄存器中传递参数。如果调用代码不知道正确的链接,它将把参数数据放在一个地方,而函数将在另一个地方查找并且只读取垃圾,因此无法正确操作。

于 2013-02-27T19:18:03.270 回答