我在dll中观察到一个具有C连接的函数.此函数返回类类型.我不确定这是如何实现的,因为C不理解课程.
我自己编写了一个示例dll和程序,并注意到VC++编译器显示了对此效果的警告,但并未阻止您.该程序能够使用此函数的GetProcAddress并调用它来接收返回的对象.类定义可供程序使用.
此外,如果我编写一个带有C链接的函数,该函数返回甚至不导出此类的类类型,则编译器不会发出任何警告.如果类定义可用,程序可以从dll使用此函数.
有关这是如何工作的任何想法?这样的行为编译器/平台是否具体?
C链接的函数可以返回无法用C表示的对象,只要它们可以在C中操作.根据我的C++设计和演变版本(第11.3.3节):
在决定实际添加到语言中的那个之前,我们考虑了类型安全联动方案的几种替代方案[Stroustrup,1988]:......
- 仅为无法使用C函数的函数提供类型安全链接,因为它们具有无法用C表示的类型.
声明具有C链接的函数仍具有C++调用语义.也就是说,必须声明形式参数,并且实际参数必须在C++匹配和歧义控制规则下匹配....如果我们为C提供特殊服务,我们就不得不向C++编译器添加一组无限的语言调用约定[用于链接到Pascal,Fortran,PL/I等]....
链接,语言间调用和语言间对象传递本质上是困难的问题,并且具有许多依赖于实现的方面.......我希望我们没有听到这件事的最后一件事.
也就是说,C++链接不是基于所涉及的类型是否是有效的C类型.这是一个有意的设计决定.它允许您创建一个用C++编译的DLL,但可以通过标头从C中使用它:
// in the header
struct Foo; // forward declaration
#ifdef __cplusplus
extern "C" {
#endif
struct Foo* create_foo();
void destroy_foo(struct Foo*);
void foo_bar(struct Foo*);
#ifdef __cplusplus
} // extern "C"
// now declare Foo
struct Foo {
void bar();
};
#endif
// in the implementation file
#include <iostream>
extern "C" {
Foo* create_foo()
{
return new Foo();
}
void destroy_foo(Foo* f)
{
delete f;
}
void foo_bar(Foo* f)
{
f->bar();
}
}
void Foo::bar()
{
std::cout << "Foo::bar() called\n";
}
Run Code Online (Sandbox Code Playgroud)
注意,在两个电话new
,delete
和std::cout
.这些都需要C++运行时.因此,实现文件必须使用C++编译,但由于函数具有C链接,因此可以从C或C++使用标头.
那么你怎么得到一个Foo
C?在这种情况下,你没有,因为没有办法以C将理解的方式在标题中完全声明它.相反,C只能看到前向声明,它会创建一个不完整的类型.C不知道不完整类型有多大,所以C函数不能创建它或直接对它们进行操作,但是C确实知道指向不完整类型的指针有多大,所以C可以操作指向不完整类型的指针类型.你可以获得更多的创造力,并实际上用C++创建POD类型,你可以直接在C中操作.
只要您只Foo*
在C中使用s,就不必在C中实际定义Foo
结构.事实上,APR使用了类似的设计("创建APR类型",我找不到更好的链接).