C++入門教程之內(nèi)聯(lián)函數(shù)與extern?"C"詳解
一. 內(nèi)聯(lián)函數(shù)
1.概念及分析
以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)調(diào)用建立棧幀的開銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率。
int Add(int a, int b) { int c = a + b; return c; } int main() { int ret= Add(1, 2); return 0; }
在我們之前使用的函數(shù)中,編譯時(shí)會建立棧幀,進(jìn)而去調(diào)用
而正如上面說的那樣,內(nèi)聯(lián)函數(shù)編譯時(shí)C++編譯器會在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)調(diào)用建立棧幀的開銷。我們可以用inline修飾后來看一下
查看方式:
1. 在release模式下,查看編譯器生成的匯編代碼中是否存在call Add
2. 在debug模式下,需要對編譯器進(jìn)行設(shè)置,否則不會展開,因?yàn)閐ebug模式下,編譯器默認(rèn)不會對代碼進(jìn)行優(yōu)化
而由于我使用的是vs2022,release模式下的匯編代碼太過簡略,我在這里就只采用debug的模式來查看。
如此設(shè)置,便能進(jìn)行查看
可以看到,與普通的函數(shù)不同,內(nèi)聯(lián)函數(shù)的確是在調(diào)用的地方展開。
2.特性
1. inline是一種以空間換時(shí)間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會用函數(shù)體替換函數(shù)調(diào)用,缺陷:可能會使目標(biāo)文件變大,優(yōu)勢:少了調(diào)用開銷,提高程序運(yùn)行效率。
2. inline對于編譯器而言只是一個(gè)建議,不同編譯器關(guān)于inline實(shí)現(xiàn)機(jī)制可能不同,一般建議:將函數(shù)規(guī)模較小(即函數(shù)不是很長,具體沒有準(zhǔn)確的說法,取決于編譯器內(nèi)部實(shí)現(xiàn))、不是遞歸、且頻繁調(diào)用的函數(shù)采用inline修飾,否則編譯器會忽略inline特性。
3. inline不建議聲明和定義分離,分離會導(dǎo)致鏈接錯誤。因?yàn)閕nline被展開,就沒有函數(shù)地址了,鏈接就會找不到。
3.宏
其實(shí),在c語言中,我們使用宏也能產(chǎn)生類似的效果
#define ADD(x,y) ((x)+(y)) int main() { int ret = ADD(1, 2); printf("%d", ret); return 0; }
但宏在實(shí)質(zhì)上已經(jīng)不是函數(shù)了,而是將ADD(x,y)作為標(biāo)識符來宏定義為字符串((x)+(y))
而宏也有其優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1.增強(qiáng)代碼的復(fù)用性。
2.提高性能。
缺點(diǎn):
1.不方便調(diào)試宏。(因?yàn)轭A(yù)編譯階段進(jìn)行了替換)
2.導(dǎo)致代碼可讀性差,可維護(hù)性差,容易誤用。
3.沒有類型安全的檢查 。
而C++中,除開短小函數(shù)使用內(nèi)聯(lián)函數(shù)來替代宏,常量定義時(shí)也可以使用const、enum
二. extern “C”
由于C++是在C的基礎(chǔ)上提供了更多的語法和特性,所以我們能不能在C++的程序中使用C靜態(tài)庫中的函數(shù)或者在C的程序中使用C++靜態(tài)庫中的函數(shù)呢?
實(shí)際上這種想法是可行的,但是我們需要進(jìn)行一些處理,這也就要使用到extern "C"
1.C++程序
依舊是以vs2022為例,我們首先需要創(chuàng)建一個(gè)靜態(tài)庫
之后我們要在靜態(tài)庫里寫一些c的函數(shù)
之后
這樣,lib文件就會在Debug中生成
C的靜態(tài)庫就處理完成了
我們再看到C++的程序
在使用C靜態(tài)庫中函數(shù)前,我們首先要包含頭文件。與以往不同,我們需要通過文件的路徑去尋找頭文件(Add.h)
通過對兩個(gè)文件的路徑進(jìn)行分析,我們可以如此來引用頭文件
#include"../DS/add.h"
其中,..代表的是前往上一層目錄
然后,我們可以使用Add函數(shù)
#include<iostream> using namespace std; #include"../Slist/sList.h" int main() { cout << Add(1, 2) << endl; return 0; }
當(dāng)我們運(yùn)行時(shí),會出現(xiàn)以上的問題,這是因?yàn)槲覀冞€沒有去鏈接靜態(tài)庫
我們需要在上述位置將靜態(tài)庫中的Debug文件夾的路徑添加上
并在上述位置加入所引用的頭文件
如此,若是在C++項(xiàng)目中引用C++靜態(tài)庫或是在C項(xiàng)目中引用C靜態(tài)庫,以上操作便能完成
而為了區(qū)別兩種語言,C++的函數(shù)會被修飾,而C不會
因此我們就要使用extern "C"來表明頭文件中的函數(shù)是用C編寫的
extern "C" { #include"../DS/add.h" }
如此,便完成了全部的操作
2.C程序
那么當(dāng)我們反過來呢?
首先我們現(xiàn)將上述的文件中的.c改為.cpp,.cpp改為.c 并分別做一下調(diào)整
注意:由于C不認(rèn)識C++的語法,我們C++靜態(tài)庫中的函數(shù)要遵循C的語法
我們應(yīng)該對靜態(tài)庫中的頭文件進(jìn)行修飾。
但由于C語言中并沒有extern "C",所以我們不能直接將函數(shù)放在其中,而是需要進(jìn)行條件編譯,使得C調(diào)用時(shí)不需要extern "C",C++調(diào)用時(shí)需要。
這里我們提供兩種方法
#ifdef __cplusplus extern "C" { #endif int Add(int a,int b); #ifdef __cplusplus } #endif
#ifdef __cplusplus #define EXTRERN_C extern "C" #else #define EXTRERN_C #endif EXTRERN_C int Add(int a,int b);
之后,別忘了重新生成一下解決方案,這樣就能實(shí)現(xiàn)C程序調(diào)用C++靜態(tài)庫了
總結(jié)
到此這篇關(guān)于C++入門教程之內(nèi)聯(lián)函數(shù)與extern "C"詳解的文章就介紹到這了,更多相關(guān)C++內(nèi)聯(lián)函數(shù)與extern "C"內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#委托所蘊(yùn)含的函數(shù)指針概念詳細(xì)解析
C#中用委托這種概念實(shí)現(xiàn)了函數(shù)指針技術(shù)而已,另外.ent提供額外的安全性,當(dāng)然也損失了靈活性2013-09-09c++實(shí)現(xiàn)逐行讀取配置文件寫入內(nèi)存的示例
這篇文章主要介紹了c++實(shí)現(xiàn)逐行讀取配置文件寫入內(nèi)存的示例,需要的朋友可以參考下2014-05-05C語言實(shí)現(xiàn)2048游戲(ege圖形庫版)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)2048游戲,ege圖形庫版,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12C++中的多態(tài)與多重繼承實(shí)現(xiàn)與Java的區(qū)別
這篇文章主要介紹了C++中的多態(tài)與多重繼承實(shí)現(xiàn)與Java的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03