解析__cdecl,__fastcall, __stdcall 的不一樣:
在函數調用過程當中,會使用堆棧,這三個表示不一樣的堆棧調用方式和釋放方式。
好比說__cdecl,它是標準的c方法的堆棧調用方式,就是在函數調用時的參數壓入堆棧是與函數的聲明順序相反的,其它兩個能夠看MSDN,不過這個對咱們編程沒有太大的做用
---------------------------------------------------------------
調用約定
調用約定(Calling convention)決定如下內容:函數參數的壓棧順序,由調用者仍是被調用者把參數彈出棧,以及產生函數修飾名的方法。MFC支持如下調用約定:
_cdecl
按從右至左的順序壓參數入棧,由調用者把參數彈出棧。對於"C"函數或者變量,修飾名是在函數名前加下劃線。對於"C++"函數,有所不一樣。
如函數void test(void)的修飾名是_test;對於不屬於一個類的"C++"全局函數,修飾名是_test@@ZAXXZ(怎麼感受像亂碼??)。
這是MFC缺省調用約定。因爲是調用者負責把參數彈出棧,因此能夠給函數定義個數不定的參數,如printf函數。
_stdcall
按從右至左的順序壓參數入棧,由被調用者把參數彈出棧。對於"C"函數或者變量,修飾名如下劃線爲前綴,而後是函數名,而後是符號"@"及參數的字節數,如函數int func(int a, double b)的修飾名是_func@12。對於"C++"函數,則有所不一樣。全部的Win32 API函數都遵循該約定。
_fastcall
頭兩個DWORD類型或者佔更少字節的參數被放入ECX和EDX寄存器,其餘剩下的參數按從右到左的順序壓入棧。由被調用者把參數彈出棧,對於"C"函數或者變量,修飾名以"@"爲前綴,而後是函數名,接着是符號"@"及參數的字節數,如函數int func(int a, double b)的修飾名是@func@12。對於"C++"函數,有所不一樣。
將來的編譯器可能使用不一樣的寄存器來存放參數。
Dll中用 __declspec(dllexport)聲明的函數:
__declspec(dllexport)只是表示這個函數是一個DLL導出函數,而__stdcall是一種函數調用約定,二者應該是沒有衝突的.
如:__declspec(dllexport) void __stdcall aTry();
c++builder和vc描述符定義的區別
在c++builder中
__cdecl的函數輸出前會帶:"_"
__stdcall無特徵,只輸出函數名
__fastcall函數輸出前帶:"@"
都無"@nn"後綴格式!
在vc中
__cdecl無特徵,只輸出函數名
__stdcall的函數輸出前會帶:"_"後綴帶:"@nn"
__fastcall函數輸出前帶:"@"後綴帶:"@nn
c++builder調用VC的dll:
在VC中編寫DLL時,使用了.def文件,在出口函數聲明時也在前面加上了__declspec(dllexport)說明。把VC生成的DLL文件放在了當前目錄下,使用BCB的命令行工具implib生成的.lib文件,具體格式爲implib bcb.lib vc.dll,再把implib根據dll生成的LIB文件加入到工程中,再在工程中加入DLL出口函數的聲明(函數名前加上了WINAPI,即__stdcall;每一個函數定義的最前面也加上了__declspec(dllimport))。
並且因爲BCB和VC++成立函數名轉換的作法不一樣。因此在VC中最好是輸出函數爲C函數的DLL,若是輸出函數是C++類,則可能沒法調用。
個人解決辦法(通過本人實驗證實的,共2種)
方法1:VC編譯c文件生成dll時導出函數頭文件加上extern "C"{}關鍵字,函數聲明和定義處再加調用約定描述符__cdecl,而後將函數聲明和定義處都加上一個下劃線就沒有問題了。
EXAMPLE:
假設我VC的dll中包含int myFunction(void),.c文件中函數實現處的正確寫法是:
__declspec(dllexport) int __cdecl _myFunction(void)
{
// add your code here
}
.h文件中函數聲明處的正確寫法以下
__declspec(dllexport) int __cdecl _myFunction(void);
BCB調用時只要包含lib文件,具體操做步驟:
運行implib bcb.lib vc.dll
project->add to...下拉框中選擇.lib類型,打開剛纔經過implib和vc的dll生成的lib文件
在工程中用到dll的.c源文件中包含該dll的頭文件
調用時直接寫 int i = myFunction(); 便可。
方法2:僅對VC編譯C文件生成dll時有效,導出函數頭文件加上extern "C"{}關鍵字。BCB的Project->option->advanced compiler下的Calling convention中選擇Stdcall就能夠直接調用VC的.c文件編譯生成的動態連接庫了。
VC調用c++builder的dll: (參考:MSDN2000)
VC中無LIB時的DLL隱式連接,製做與VC++相符合的LIB函數符號輸入庫(轉)請你們注意!這種方法只能應用於輸出爲C格式的__stdcall調用方式!
1.使用VC++的工具DUMPBIN將DLL中的導出函數表導出到必定義(.DEF)文件
EXAMPLE:
DUMPBIN VideoDeCoder.dll /EXPORTS /OUT:VideoDeCoder.def
2.將導出的.DEF文件整理爲一符合.DEF個數的函數導出文件(整理過程巨亂巨複雜,懶得舉例了,後面有簡便方法^_^)
3.使用VC++的LIB工具,帶/DEF:(.def文件名) /MACHINE:IX86(80X86機器),就輸出符合VC++格式的的LIB文件了.
EXAMPLE:
LIB/DEF:VideoDeCoder.def /MACHINE:IX86
4.鏈接時帶上LIB文件連接;注意的是當有些動態庫DUMPBIN的只有函數名,無"@nn"的參數格式,如C++Builder寫的DLL,輸出就只有函數名符號,連接時就會報錯:
error LNK2002:unresolved external symbol "functionname@nn"
提示程序中引入的函數符號沒法識別,這時只要將DEF文件中相應的函數名稱改成functionname@nn方式,從新創建LIB,從新連接便可.
這樣就製做成功了符合VC調用方式的LIB了!
要值得一說的是!BORLAND C++BUILDER有一個很好的工具IMPDEF能夠直接將DLL中的函數輸出到.DEF文件中,這種方法只能應用於輸出爲C格式的__stdcall調用方式,只要作一點點修改就能夠成爲符合VC的DEF文件!
IMPDEF xxx.def xxx.dll
只要將BCB的DEF文件中函數申明格式轉換爲vc識別的格式就能夠利用LIB工具生成LIB;要使用C分格輸出(extern "C")纔是必須的!並且別忘了在DEF文件中的函數申明不要帶「_」啊!:)否則會出現error LNK2001的連接錯誤!
vc調用bcb的我沒試過,不過能夠參照上面的格式本身改改好了:)c++