天天看點

深剖函數重載——C++基礎篇

目錄

  • ​​傳統藝能????​​
  • ​​程式的運作機制????​​
  • ​​函數重載的深度内涵????​​
  • ​​extern “C”????​​
  • ​​C 調 C++?????​​
  • ​​靜态庫的建立????​​
  • ​​引用????​​

傳統藝能????

小編是雙非大學大一菜鳥不贅述,歡迎大佬指點江山

深剖函數重載——C++基礎篇

程式的運作機制????

我們之前學習過程式的預處理機制,預處理這步會去掉注釋,宏替換,頭檔案展開以及條件編譯(​​詳見俺之前的筆記​​),假如這裡有一個程式包含了== new.h , new.cpp 和 test.c ,預處理完了變成 == new.i , test.i

接着編譯步驟會去檢查文法并生成彙編代碼,程式報錯會在編譯這一步發生,編譯處理完後變成== new.s, test.s==,是以之前說的預設參數為什麼要在聲明(.h)給出而不在定義(.cpp)給出就是因為如果有預設參數,函數的聲明和調用就應該比對,否則編譯就會報錯。

彙編出的代碼就是指令級的語言,也就是代碼轉到反彙編後的一句一句代碼,編譯沒問題後就會将代碼轉換成指令,這些指令都是給 CPU 準備的,CPU就是去執行指令的,那他是怎麼支援的呢?CPU對每條指令他都支援了一個指令級,每個指令級要做什麼事他都可以做,比如調用函數的 call 指令等等。當然,彙編代碼不是 CPU 認識的 0,1 二進制代碼,CPU:請打開麥克風交流!是以彙編就是翻譯出二進制機器碼,這一步會生成 == new.o, test.o==。

深剖函數重載——C++基礎篇

連結為什麼說是連結而不是直接合并呢?其實他的本質就是去連結庫并找到調用函數位址,連結對應上合并在一起。我們從兩個方面來看,我們預處理階段就把 new.h 展開在頭上了,也就是我們有了 .h 裡面函數的聲明了,而我們在調用他裡面包含的函數名時,函數一來就會先建立棧幀,有棧幀就必定有位址,有位址才能被調用。

連結過程還會生成一個符号表和函數調用指令,符号表主要記錄了函數名稱和函數位址的映射。這些内容是為了在有人調用這個函數的時候能夠執行 call 指令(call + 函數位址 是在調用函數),如果出現 “連結錯誤” 那他并不是文法錯誤,可能是聲明了函數而沒有寫定義之類的讓連結過程找不到。

函數重載的深度内涵????

我們之前說C++裡面特色的函數重載,而C語言不支援,那C++到底是如何支援的?而C語言又是為何不支援?要明白這些問題首先要知道程式的運作機制包括預處理,編譯,彙編,連結

==是以C語言之是以不支援函數重載是因為C語言函數名是用的原來自己的名字 ,就會發生沖突!==而C++支援函數重載是因為C++會發生函數名修飾,修飾基本規則是 _Z + 函數名 + 類型首字母,比如 void func(int a,double b)命名出來就是 _Zfuncid,Linux環境下是這樣命名的。

連結時找到函數的位址來填上,當然他也可以連結其他庫,比如别人開源寫了一個資料庫,庫裡面又一些 API ,在C和C++裡面我們叫他靜态庫或動态庫。庫是 C 的 cpp 能調用,是 cpp 的 C 也能調用,這種交叉調用這麼神奇?

深剖函數重載——C++基礎篇

但是交叉調用有一個鴻溝,其實這個過程和上面一樣,編譯好了到符号表裡面去找,這裡會在連結時去對應庫裡面去找,直接找是找不到的!和函數重載是一樣的,那我該怎麼找啊?這裡又引入一個新的概念 extern “C”

extern “C”????

這個功能十分有用處,因為在C++出現以前,很多代碼都是C語言寫的,而且很底層的庫也是C語言寫的,為了更好的支援原來的C代碼和已經寫好的C語言庫,需要在C++中盡可能的支援C,而extern "C"就是其中的一個政策。

對于 cpp 内函數名是修飾過的,C 又是沒修飾的 , extern “C”就可以改變連結或編譯方式來幫助我們 C 調 cpp 或者 cpp 調 C。

C++代碼調用C語言代碼,在C++的頭檔案中使用或者在多個人協同開發時,可能有的人比較擅長C語言,而有的人擅長C++,這些個情況下 extern “C” 就有大顯身手的機會。

如此一來我們 C++ 想調 C 就簡單了,直接加上一句

extern "C"
{
   #include "file"//file檔案名,如.lib、.h
}      

他就是在告訴編輯器聲明的函數是 C 函數,要用 C 的方式去連結調用。C 調 C++ 有一些些不一樣了,我們可以把之前的條件編譯的宏拿來好好玩玩

#ifdef __cplusplus
     #define _C extern "C"
#else
     #define _C
#endif      

__cplusplus 是C++天生就自己定義的辨別符,代碼中的 extern “C” 全部替換成 _C,條件編譯隻要滿足C++條件就放出後面帶有 extern “C” 聲明的 _C 宏辨別。當然 extern “C” 可以放在函數名前面也可以括起來多個函數聲明。

C 調 C++?????

C程式是可以調用 C++ 的,但是并不常見,已知的一個 google 的項目,他們寫的 tc_malloc ,用來替代 C語言裡面的 malloc,他們覺得多線程下 tc_malloc 比 malloc 更高效,而 tc_malloc 的實作基礎是 C++,如果一個C語言項目想用他也是可以的,隻需要對暴露的關鍵函數加上 extern “C”就行。

深剖函數重載——C++基礎篇

靜态庫的建立????

我們在 C++ 項目裡面直接引用 C 的頭檔案是施行不通的,我們可以自己建立一個靜态庫,以 vs 為例,空項目基礎上右鍵屬性,正常選中配置類型改為靜态庫

深剖函數重載——C++基礎篇

debug 下生成的就不是 .exe 而是 .lib 了,他就是靜态庫,我們要想在 C++ 程式裡面連結 C 的靜态庫,一樣的右鍵屬性,連結器裡面正常選中附加庫目錄,可以在電腦中浏覽想添加的庫

深剖函數重載——C++基礎篇

然後再找到輸入欄的附加依賴項,将添加的靜态庫名稱加到這裡的最前面,前後用分号隔開一下更好。

深剖函數重載——C++基礎篇

原理就是我們程式連結時會去目錄下找庫,找到靜态庫 .lib 裡面有對應的符号表,映射和 C++ 一樣的指令即可。

引用????

這裡的引用不是新定義的一個變量,而是給已經存在的變量取了一個别名,編譯器不會為引用變量開辟空間,他和他的引用變量共用一塊記憶體空間,就好比你叫某某某,但江湖上人們都叫你帥哥或者美女。

int a = 1;
int b = a;      

這裡 b 就是 a 的引用也叫做 a 的别名,他們的位址都是一樣的,他的價值就是比如我們需要造一個含有指針參數的函數,取位址很麻煩的,我們可以讓形參是實參的别名,這樣就不用取位址就爽多了,引用的使用還是非常友善的。

繼續閱讀