2011-01-20 98 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類型」,我找不到更好的鏈接)。