C++函數(shù)調(diào)用有三種常見方式:thiscall,__cdecl,__stdcall
專注于為中小企業(yè)提供網(wǎng)站設(shè)計制作、成都做網(wǎng)站服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)綏化免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上1000+企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。
今天看了篇介紹的文章,才比較清楚了點。thiscall,用于類的成員函數(shù)調(diào)用,
__thiscall對每個函數(shù)都增加了一個類指針參數(shù)
class aa
{
void bb(int cc);
};
實際上bb的函數(shù)原形是void bb(aa this, int cc);
以前知道類的成員函數(shù)在調(diào)用時會傳入一個this指針,而不曉得thiscall就是專門指定了這種調(diào)用方式。__cdecl調(diào)用方式即為C,C++默認的調(diào)用方式。
void Input( int m,int n);/*相當于void __cdecl Input(int m,int n);*/
其特點是:1,由主調(diào)用函數(shù)進行參數(shù)壓棧并且恢復(fù)堆棧;2,在主調(diào)用函數(shù)中進行實參的壓棧并且順序是從右到左;3,由于主調(diào)用函數(shù)管理堆棧,所以可以實現(xiàn)變參函數(shù)。
__stdcall則是標準調(diào)用方式,實際上就是PASCAL,CALLBACK,WINAPI ,其特點是:_主調(diào)用函數(shù)中負責(zé)壓棧,在被調(diào)用函數(shù)中負責(zé)彈出堆棧中的參數(shù),并且負責(zé)恢復(fù)堆棧。因此不能實現(xiàn)變參函數(shù),參數(shù)傳遞是從右到左。另外,命名修飾方法是在函數(shù)前加一個下劃線(_),在函數(shù)名后有符號(@),在@后面緊跟參數(shù)列表中的參數(shù)所占字節(jié)數(shù)(10進制),如:void Input(int m,int n),被修飾成:_Input@8 。
首先這個是C++的代碼,C是沒有類的概念,也不會有成員函數(shù)的概念。
void在這里代表該成員函數(shù)沒有返回值。
fun_c()函數(shù)所在的代碼文件命名為xxx.c,fun_Cplusplus()函數(shù)所在的代碼文件命名為yyy.cpp,你先把yyy.cpp和其他所有cpp文件一起編譯鏈接一遍,沒有error之后,再加入xxx.c一起編譯鏈接。在fun_c()的頭文件里面不需要包含fun_Cplusplus()的頭文件,只需要在xxx.c開頭聲明一下fun_Cplusplus()是外部函數(shù)就可以了:
extern fun_Cplusplus();
如何調(diào)用C語言寫的庫,如a.lib等,有對應(yīng)的庫頭文件a.h。假設(shè)a.h中定義了函數(shù):
int
WhyCoding(int
a,
float
b);
做法是,
/*
cpp_a.h
*/
extern
"C"
{
#include
"a.h"
}
或
/*
cpp_a.h
*/
extern
"C"
{
int
WhyCoding(int
a,
float
b);
/*
重定義所有的C函數(shù)
*/
}
從上面可以看出,extern
"C"
是用在C和C++之間的橋梁。之所以需要這個橋梁是因為C編譯器編譯函數(shù)時不帶
函數(shù)的類型信息,只包含函數(shù)符號名字,如C編譯器把函數(shù)int
a(float
x)編譯成類似_a這樣的符號,C連接器只要
找到了調(diào)用函數(shù)的符號,就可以連接成功,它假設(shè)參數(shù)類型信息是正確的,這是C編譯連接器的缺點。而C++
編譯器為了實現(xiàn)函數(shù)重載,編譯時會帶上函數(shù)的類型信息,如他把上面的a函數(shù)可能編譯成_a_float這樣的
符號為了實現(xiàn)重載,注意它還是沒有帶返回值得信息,這也是為什么C++不支持采用函數(shù)返回值來區(qū)別函數(shù)
重載的原因之一,當然,函數(shù)的使用者對函數(shù)返回值的處理方式(如忽略)也是重要原因。
基于以上,C調(diào)用C++,首先需要用封裝函數(shù)把對C++的類等的調(diào)用封裝成C函數(shù)以便C調(diào)用,于是extern
"C"
的
作用是:讓編譯器知道這件事,然后以C語言的方式編譯和連接封裝函數(shù).(通常是把封裝函數(shù)用C++編譯器按C++
方式編譯,用了extern
"C"
后,編譯器便依C的方式編譯封裝接口,當然接口函數(shù)里面的C++語法還是按C++方式
編譯;對于C語言部分--調(diào)用者,還是按C語言編譯;分別對C++接口部分和C部分編譯后,再連接就可以實現(xiàn)C
調(diào)用C++了).
相反,C++調(diào)用C函數(shù),extern
"C"
的作用是:讓C++連接器找調(diào)用函數(shù)的符號時采用C的方式,即使用_a而不是
_a_float來找調(diào)用函數(shù)。
void CallMyFun(FunType fp,int x);是一個包含函數(shù)指針的函數(shù)!
fp只是函數(shù)指針的名稱,是 CallMyFun函數(shù)的形參,這個名稱你可以隨便取的
當調(diào)用CallMyFun(MyFun1,10);//假設(shè)調(diào)用此變量時,
fp指代的就是MyFun1函數(shù),而MyFun1的參數(shù)哪里來?就是通過CallMyFun的第2個參數(shù)傳遞進來的,這里是10
所以運行CallMyFun(MyFun1,10);函數(shù),其實就是運行了call MyFun1(10)
所以運行CallMyFun(MyFun2,20);函數(shù),其實就是運行了call MyFun2(20)
所以fp(x)指代的是一個函數(shù),如果要輸出他的結(jié)果,那在定義MyFun1,MyFun2時,函數(shù)就需要有返回值,而不能用void
不管是不是靜態(tài)的,都不能直接調(diào)用
而是要加一層C++的封裝。
而且封裝的函數(shù),必須加extern "C"才可以。