C++多態(tài)與虛擬之C++編譯器對函數名的改編(Name?Mangling)
如果函數名稱都相同(也就是被overloaded),編譯器在面對你的函數喚起動作時,究竟是如何確定調用哪個函數實體呢?事實上,編譯器把所有同名的overloaded functions視為不同的函數,并且以特殊方式對它們的函數名稱做了手腳,以四個Add()函數為例:
int Add(int a, int b); long Add(long a, long b); double Add(double a, double b); float Add(float a, float b);
Visual C++編譯器真正為這四個函數所編碼出來的函數名稱是:
?Add@@YAHHH@Z ?Add@@YAJJJ@Z ?Add@@YANNN@Z ?Add@@YAMMM@Z
再以 CPoint 的兩個 x() 為例:
class CPoint
{ public:
...
float x();
void x( float xval );
};編譯器真正為它們編出來的函數名稱是(其中包含class名稱,參數個數和參數類型):
?x@CPoint@@QAEMXZ ?x@CPoint@@QAEXM@Z
這樣的“名稱改編”行為稱為“name manging”。讓人遺憾的是,不同編譯器有著不同的name manging作法。這當然不好,表示我以Microsoft C++編譯出來的程序沒辦法調用一個以Borland C++編譯器完成的函數。換句話說,函數的名稱并不存在著binary standard,這就嚴重影響了software components的發(fā)展。Naming Mangling 不只用于overloaded functions身上,C++程序中所有的global函數以及classes中的所有members,都會被施以naming mangling手術。如果要抑制naming mangling的作用,就必須加上關鍵字extern“C”以修飾。
extern "C":對于程序員來說,通常不需要關心名稱改編(Name Mangling)這個問題。但是,當你的C++程序需要導出某些功能供其他程序或庫使用時,名稱改編就會成為一個問題。在C++程序中,可以導出的東西主要是函數和類。雖然也可以導出數據,但根據“數據封裝”的原則,導出數據是非常罕見且應該避免的做法。 無論類是否被導出,它們的名稱都會被改編。但是,對于函數來說,當我們試圖導出它們時,我們不希望編譯器對它們進行名稱改編。這是因為我們不希望這些函數的使用者被限制使用“與函數設計者相同的開發(fā)工具”。畢竟,目前各家C++編譯器廠商并沒有協(xié)調出一個統(tǒng)一的名稱改編方法。 因此,對于即將導出的函數,為了抑制名稱改編的作用,我們必須加上特殊的修飾詞`extern "C"`。這樣做可以讓編譯器知道這些函數應該使用C風格的鏈接,從而避免名稱改編。這樣,其他語言或庫就可以正確地調用這些函數了。例如:
extern "C" int Add(int a, int b);
在Windows DLLs中,使用C++編寫的DllMain()等callback函數需避免C++編譯器進行name mangling,因此需使用extern "C"。這樣可以確保函數名稱和格式固定,便于系統(tǒng)回呼。
extern "C"
int APIENTRY 7 DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
{
...
}到此這篇關于C++多態(tài)與虛擬之C++編譯器對函數名的改編(Name Mangling)的文章就介紹到這了,更多相關C++編譯器對函數名的改編內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

