2010-06-04 96 views
6

我只是想進一步理解extern C函數。更好地理解extern「C」函數

據我所知,extern C函數總是一個函數,你正在嘗試從已編譯的應用程序調用。可執行文件,靜態或動態庫。

extern "C" 
{ 
    HRESULT CreateDevice(); 
    typedef HRESULT (*CREATEDEVICE)(); 

    HRESULT ReleaseDevice(); 
    typedef HRESULT (*RELEASEDEVICE)(); 
} 

所以我的問題是...

我的理解是否正確?

它總是必須是一個C函數指針??'

爲什麼你必須爲每個函數使用typedef?

我推測當你使用GetProcAddress()。您正在爲特定應用程序HEAP分配內存,而不是您正在調用它的內存。因此,你必須從堆中釋放它?

+0

您是否看到此問題? http://stackoverflow.com/questions/67894/why-do-we-need-extern-c-include-foo-h-in-c – Jujjuru 2010-06-04 03:41:33

回答

1

它不一定是一個函數指針。您可以正常指定函數聲明,並以extern "C"爲前綴,如some Microsoft examples中所示。

如果您使用GetProcAddress()您沒有分配任何內存。您只需獲取已加載到內存中的DLL內部函數的內存地址(假設爲LoadLibrary())。

即使使用函數指針(如由GetProcAddress的返回),你不使用typedef,它只是代碼看起來很醜陋,沒有它。想弄清楚寫什麼也很困難。我認爲這會是這樣的:

void (*pReleaseDevice)() = (void (__cdecl *)(void))GetProcAddress(hInstance, "ReleaseDevice"); 
+0

請注意__cdecl是Microsoft特定的。 – 2010-06-04 03:55:15

+2

@Billy ONeal:「GetProcAddress」和Visual Studio也是如此。 – dreamlax 2010-06-04 04:07:29

+0

GetProcAddress不是Microsoft特定的,但它是Windows特定的。例如,我可以使用帶有MinGW的GetProcAddress,但不能使用__cdecl。 – 2010-06-04 04:12:09

0

的extern「C」 {}是一個C++慣例,宣佈封閉函數是C函數 - 不是C++函數。 C++有一個與C有衝突的命名約定。如果你有一個用C編寫的庫,並且想在C++程序中使用它,你必須使用extern「C」{}讓編譯器知道這些是C函數。如果庫是用C++編寫的,我相信extern「C」{}會導致錯誤。

請注意,extern有多種含義 - 這種特定的情況是C++約定,與extern的不同用途無關。例如,

​​

與extern「C」{}具有完全不同的含義。

typedef與extern「C」{}問題是分開的。通過typedefs,您可以爲常用類型創建更有意義的別名。例如,聲明結構通常是一個冗長的過程。我可以用一個typedef來縮短:

struct mystruct {int a; int b}; 
typedef struct mystruct returncode; 
// I can now declare a variable as type 'returncode' 
returncode a; 

因此,在您的示例HRESULT是真的(* CreateDevice的)(),但我認爲你必須把它的功能之前(而不是之後)的別名。

4

extern「C」有兩個含義。首先,它聲明函數的符號名稱不是「name mangled」以支持C++。其次,它告訴編譯器該函數使用C調用約定而不是PASCAL調用約定來調用。不同的是當返回地址被壓入堆棧時。使用錯誤的調用約定會導致應用程序崩潰。

此聲明適用於編譯器,不適用於鏈接器。因此,extern C函數可以存在於您自己的模塊或二進制庫中:函數實現的實際字節的來源由鏈接器解析。如果函數簽名被聲明爲常規C++函數而不是extern C,那麼編譯器將對函數簽名中的符號名稱進行編碼以對類型信息進行編碼。這將使其與其他C++編譯器生成的目標代碼不兼容。因此,創建一個外部C函數允許您以二進制形式在編譯器之間共享代碼。請注意,您不能以這種方式公開成員函數,只能使用舊式的C函數。

0

指定extern "C"鏈接的一個重要方面是函數名稱不會被損壞,這是C++名稱的默認值。

爲了讓您的圖書館的功能,能夠使用GetProcAddress被加載,你需要或者功能添加到.def file,使用__declspec(dllexport)或使用extern "C"

0

爲了回答,爲了:

  • 外部的 「C」 函數是從C++用於互操作以C。使用它們會導致C代碼可以調用該函數。由於Windows API是C API,所有函數都是extern「C」以確保C和C++代碼可以使用該API。

  • 爲了使C++程序與其他語言(包括C)一起作爲慣例進行互操作,函數使用extern「C」導出。這就是爲什麼很多dll代碼都這樣做的原因。但這不是技術要求。

  • 所以不,它不一定是C函數指針。

  • 您不必使用typedef。

提供的示例代碼來自發布DLL導出兩次的頭文件 - 一次是導出的一組extern「C」方法,以便可以靜態鏈接dll。另一個是一組函數指針類型,以便可以動態加載dll,以及與GetProcAddress一起使用的函數指針類型。