2011-01-20 96 views
4

我在一个有C链接的dll中观察了一个函数。这个函数返回类的类型。我不确定这是如何实现的,因为C不了解课堂。
我写了一个示例DLL和程序自己,并指出VC++编译器显示此效果的警告,但不阻止你。程序能够GetProcAddress这个函数并且调用它来接收返回的对象。课程定义已提供给程序。另外,如果我编写一个C链接的函数,该函数返回一个类类型,甚至不会导出该类,编译器不会发出任何警告。如果类定义可用,程序可以从dll中使用该函数。
有关如何工作的任何想法?这样的行为编译器/平台是特定的吗?具有C连接能够返回类类型的函数?

+1

有一些技巧,那就是如何在C++中实现控制的反转。你有一些链接或例子吗? – 2011-01-20 08:02:04

+1

类签名会很有用。否则,我们只是猜测。 – 2011-01-20 08:28:01

+0

你知道类型不存在于二进制级别吗? – 2016-05-10 15:23:04

回答

10

您误解了extern "C"的行为。

它只通过阻止name mangling影响目标文件中函数的名称。它不会产生“更多C”或“更少C++”的函数。 extern "C"向C++函数添加的唯一附加限制是不应重载。

0

一个类对象基本上只是一个struct对象,为vtbl等提供了一些额外的“隐藏”成员。

但是,我不确定你的意思是“程序可以使用此函数,只要类定义可用”。 C会在看到class Blah { ... };时发出编译器错误。

+0

对不起,我感到困惑。该程序是用C++编写的,它使用的dll有一个C接口。我已经在上面解释了Max Lybbert的回复。 – 2011-01-24 14:27:28

4

有可能与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"; 
}  

注到newdeletestd::cout呼叫。这些都需要C++运行时。因此,实现文件必须用C++编译,但由于函数具有C链接,因此可以使用C或C++头文件。

那么如何在C中获得Foo?在这种情况下,你不这样做,因为没有办法在头文件中以C会理解的方式完全声明它。相反,C只能看到前向声明,这会创建一个不完整的类型。 C不知道不完整类型有多大,所以C函数不能直接创建它或直接对它们进行操作,但C知道指向不完整类型的指针有多大,因此C可以在指向不完整类型的指针类型。你可以得到更多的创造性和实际创建C++ POD类型,你可以直接在C.

只要你只在C使用Foo* s运行在

,你没有真正定义在C Foo结构。碰巧APR uses a similar design(“创建APR类型”,我找不到更好的链接)。