具有C链接的函数能够返回类类型吗?

时间:2011-01-20 07:54:00

标签: c++ visual-c++

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

3 个答案:

答案 0 :(得分:10)

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

它只会阻止name mangling影响目标文件中函数的名称。它既没有“更多C”或“更少C ++”的功能。 extern "C"添加到C ++函数的唯一额外限制是不应该重载。

答案 1 :(得分:5)

具有C链接的函数可以返回无法用C表示的对象,只要它们可以在C中操作。根据我的 Design& amp; 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*,就不必在C中实际定义Foo结构。APR uses a similar design(“创建APR”输入“我找不到更好的链接”。

答案 2 :(得分:0)

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

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