簡體   English   中英

更好地理解extern“C”函數

[英]better understanding of extern “C” functions

我只是想進一步了解extern C函數。

根據我的知識,extern C函數始終是您正在嘗試從已編譯的應用程序調用的函數。 可執行文件,靜態庫或動態庫。

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

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

所以我的問題是......

我的理解是否正確?

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

為什么必須為每個函數使用typedef?

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

extern“C”有兩個含義。 首先,它聲明函數的符號名稱不是“名稱損壞”以支持C ++。 其次,它告訴編譯器使用C調用約定而不是PASCAL調用約定調用該函數。 差異與在堆棧上推送返回地址的時間有關。 使用錯誤的調用約定會使您的應用程序崩潰。

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

它不必是函數指針。 您可以正常指定函數聲明,並以extern "C"作為前綴,如某些Microsoft示例所示。

如果使用GetProcAddress() ,則不會分配任何內存。 您只需獲取DLL中已加載到內存中的函數的內存地址LoadLibrary()可能是LoadLibrary() )。

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

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

extern“C”{}是一個C ++約定,用於聲明所包含的函數是C函數 - 而不是C ++函數。 C ++的命名約定略有不同,與C沖突。如果你有一個用C語言編寫的庫並想在C ++程序中使用它,你必須使用extern“C”{}讓編譯器知道這些是C函數。 如果庫是用C ++編寫的,我相信extern“C”{}會導致錯誤。

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

extern int count;

與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)()的別名,雖然我相信你必須把它放在函數之前(而不是之后)。

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

為了能夠使用GetProcAddress加載庫的函數,您需要將函數添加到.def文件 ,使用__declspec(dllexport)或使用extern "C"

要按順序回答:

  • extern“C”函數用於與C ++中的C互操作。 使用它們的結果是C代碼可以調用該函數。 由於Windows API是一個C API,所有函數都是extern“C”,以確保C和C ++代碼可以使用API​​。

  • 為了使c ++程序與其他語言(包括C)互操作作為約定,使用extern“C”導出函數。 這就是為什么很多DLL代碼都會這樣做的原因。 然而,這不是技術要求。

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

  • 您也不必使用typedef。

提供的示例代碼來自頭文件,該頭文件兩次發布DLL的導出 - 一次作為導出的外部“C”方法的集合,以便dll可以靜態鏈接。 另一個作為一組函數指針類型,這樣dll可以動態加載,而函數指針類型與GetProcAddress一起使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM