带有C语言绑定的静态成员函数?
Posted
技术标签:
【中文标题】带有C语言绑定的静态成员函数?【英文标题】:static member function with C language binding? 【发布时间】:2016-03-06 08:49:49 【问题描述】:以下 C++ 代码使用 Visual C++ 和 g++ 编译:
struct S
static void foo();
;
extern "C"
void S::foo()
struct T
static void foo();
;
extern "C"
void T::foo()
auto main() -> int
S().foo();
T().foo();
有效吗?
如果它是有效的,因为实现可能在一个单独的翻译单元中,这是否意味着静态成员函数总是具有与 C 函数相同的调用约定(如果不是,它如何不暗示)?
【问题讨论】:
有趣...seems to compile,如果我正确理解了this answer 的第 7 点,在这种情况下extern "C"
将被忽略。另外,在cppreference.com 上,提到“当类成员声明和成员函数类型声明出现在“C”语言块中时,它们的链接仍然是“C++””
【参考方案1】:
静态成员函数与 C 函数具有相同的调用约定。但是,名称修改适用。因此,即使您成功地将静态成员声明为 extern "C"
,当您尝试将其与调用该函数的 C 代码链接时,链接器也可能找不到它。
您可以轻松地做的是声明一个包装器/存根,该包装器/存根从普通函数调用静态成员。此外,您可以将静态成员函数的地址分配给普通函数指针。
【讨论】:
请注意,虽然在实践中静态成员函数通常具有与 C 函数相同的调用约定,但标准并不能保证这一点。虽然我不知道详细信息,但请参阅此 SO 答案中的 cmets,以了解显然是这种情况的一个实例:***.com/a/1738425/12711 您引用的示例试图将非静态成员函数转换为普通函数。由于成员函数中隐含的 this 指针,这将不起作用。 我的意思是说,“不幸的是,我被静态方法所困扰,没有与'C'函数相同的调用约定......”。该评论是针对先前对答案的编辑而发布的,该答案提到静态成员函数通常与extern "C"
函数一样有效。【参考方案2】:
C++11 7.5/4《联动规范》
在确定语言链接时忽略 C 语言链接 类成员的名称和类成员的函数类型 功能。
因此,您的示例在没有格式错误或错误的意义上是有效的,但extern "C"
应该对S::foo()
或T::foo()
没有影响。
【讨论】:
【参考方案3】:不,它被忽略了,问题是 name mangling(链接阶段的函数命名)。所以诀窍是定义一个 C 函数并使用您的 C++ 静态方法作为存根来调用它,如下所示:
struct S
static void foo();
;
extern "C" void S_foo_impl();
void S::foo() S_foo_impl();
auto main() -> int
S::foo();
当然,S_foo_impl
应该在外部 C 模块中定义。
【讨论】:
鉴于问题中的代码不仅可以编译,而且可以链接,我不太明白名称修改可能是个问题。对我来说,标准的措辞“在确定类成员名称的语言链接和类成员函数的函数类型时忽略了 C 语言链接”。 (在another answer 中给出)表示extern "C"
中唯一受尊重的部分是extern
,无论如何这是默认值。我错过了什么吗?
为了能够与重载正确链接,C++ 通过在名称中编码类型来破坏函数名称,即像 int f(float)
这样的 C++ 函数在对象模块中被命名为 f_int_float
之类的东西,这是为了能够检索到正确的功能。请记住,链接器通常对类型一无所知。在 C++ 中声明 extern "C"
,防止名称混淆。当你定义一个 C++ 方法时,根据定义它应该被破坏(extern "C"
被忽略)。这个技巧是使用声明为 C 链接的全局函数(不是任何类型的方法)。这更清楚了吗?
谢谢,我知道 mangling 是什么名字。如前所述,上述内容没有链接问题。只是为了确保我使用单独的编译和函数返回值进行了测试,并且它适用于 Visual C++ 和 g++,这与没有名称修改的情况相反。
它之所以有效,是因为您使用 C++ 编译所有内容。您不能在 C 中编译名为 S::foo
的函数。 extern "C"
是混合 C++ 和 C。如果你用 C++ 编译所有代码;就像您从未定义过extern "C"
一样。我错过了什么吗?
哦,我明白了。好的,您错过了extern "C"
的最常见原因,即使用 C 语言绑定(和调用约定,尽管实际上是相同的)定义回调。我什至没有想过让 C 代码按名称调用该函数,但现在我明白这就是您所说的。对不起。以上是关于带有C语言绑定的静态成员函数?的主要内容,如果未能解决你的问题,请参考以下文章