C++基礎(chǔ)——內(nèi)聯(lián)函數(shù)-創(chuàng)新互聯(lián)

以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開(kāi),沒(méi)有函數(shù)壓棧的開(kāi)銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率

我們提供的服務(wù)有:成都做網(wǎng)站、成都網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、京口ssl等。為上千企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的京口網(wǎng)站制作公司

注意:內(nèi)聯(lián)只是將函數(shù)定義為內(nèi)聯(lián),相當(dāng)于給了編譯器一種選項(xiàng),編譯器是否使用內(nèi)聯(lián)完全由編譯器自己決定。一般而言,只要滿足一定要求的函數(shù)才會(huì)使用內(nèi)聯(lián)?

我們通過(guò)查看反匯編的形式來(lái)觀察內(nèi)聯(lián)函數(shù)和非內(nèi)聯(lián)函數(shù)在底層的實(shí)現(xiàn),假定我們實(shí)現(xiàn)了一個(gè)加法函數(shù)Add(int int)如下所示

int Add(int left, int right)
{
    return left + right;
}

int main()
{
    int a = 10;
    int b = 20;

    int ret = Add(a, b);

    return 0;
}

此時(shí)未加inline關(guān)鍵字,使用g++編譯這段代碼并使用objdump查看反匯編得到匯編為

0000000000400521
: 400521: 55 push %rbp // %rbp入棧,保存上一個(gè)棧幀的棧底地址 400522: 48 89 e5 mov %rsp,%rbp // %rsp值給%rbp,%rbp保存當(dāng)前棧幀棧底地址 400525: 48 83 ec 10 sub $0x10,%rsp // %rsp-0x10,為main函數(shù)開(kāi)辟16個(gè)字節(jié)棧幀 400529: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) // 將10 保存在棧底-4地址處 400530: c7 45 f8 14 00 00 00 movl $0x14,-0x8(%rbp) // 將20 保存在占地-8位置處 400537: 8b 55 f8 mov -0x8(%rbp),%edx // 將20 保存到寄存器%edx內(nèi) 40053a: 8b 45 fc mov -0x4(%rbp),%eax // 將10 保存到寄存器%eax內(nèi) 40053d: 89 d6 mov %edx,%esi // 將20 傳遞到寄存器%esi內(nèi)作為第二個(gè)參數(shù) 40053f: 89 c7 mov %eax,%edi // 將10 傳遞到寄存器%edi內(nèi)作為第一個(gè)參數(shù) 400541: e8 c7 ff ff ff callq 40050d<_Z3Addii>// call函數(shù)Add實(shí)現(xiàn)函數(shù)調(diào)用 400546: 89 45 f4 mov %eax,-0xc(%rbp) // 將%eax中的結(jié)果(由Add返回)保存到棧上(ret) 400549: b8 00 00 00 00 mov $0x0,%eax // 將0傳入%eax作為main函數(shù)返回值 40054e: c9 leaveq // 恢復(fù)%rsp和%rbp 40054f: c3 retq
000000000040050d<_Z3Addii>:
  40050d:	55                   	push   %rbp            // 將main函數(shù)的棧底地址入棧
  40050e:	48 89 e5             	mov    %rsp,%rbp       // %rsp保存當(dāng)前棧底
  400511:	89 7d fc             	mov    %edi,-0x4(%rbp) // 將參數(shù)一入棧
  400514:	89 75 f8             	mov    %esi,-0x8(%rbp) // 將參數(shù)二入棧
  400517:	8b 45 f8             	mov    -0x8(%rbp),%eax // 將參數(shù)二保存到寄存器%eax
  40051a:	8b 55 fc             	mov    -0x4(%rbp),%edx // 將參數(shù)一保存到寄存器%edx
  40051d:	01 d0                	add    %edx,%eax       // 完成 10 + 20,并將結(jié)果保存到%eax中
  40051f:	5d                   	pop    %rbp            // 從棧中彈出main函數(shù)棧底地址并保存到%rbp
  400520:	c3                   	retq                   // 從棧中彈出返回地址并返回main

可以看到,對(duì)于普通的函數(shù)調(diào)用,會(huì)使用call指令去調(diào)用位于40050d處的<_Z3Addii>,此時(shí)會(huì)為函數(shù)Add開(kāi)辟棧幀,會(huì)帶來(lái)一定的開(kāi)銷

接著看一下inline版本的Add函數(shù),由于g++默認(rèn)不使用內(nèi)聯(lián),需要我們做一些處理

inline int Add(int left, int right) __attribute__((always_inline));

inline int Add(int left, int right)
{
    return left + right;
}

int main()
{
    int a = 10;
    int b = 20;

    int ret = Add(a, b);

    return 0;
}

將 __attribute__((always_inline))加在聲明后,可以強(qiáng)制g++編譯器使用內(nèi)聯(lián)

同樣使用objdump獲得反匯編如下,并且所得到的反匯編內(nèi)<_Z3Addii>已經(jīng)不存在了

000000000040064d
: 40064d: 55 push %rbp 40064e: 48 89 e5 mov %rsp,%rbp 400651: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) // 10 保存到棧上(rbp-4)a 400658: c7 45 f8 14 00 00 00 movl $0x14,-0x8(%rbp) // 20 保存到棧上(rbp-8)b 40065f: 8b 45 fc mov -0x4(%rbp),%eax // 10 保存到寄存器%eax內(nèi) 400662: 89 45 f0 mov %eax,-0x10(%rbp) // 將10保存到棧上(rbp-16)left 400665: 8b 45 f8 mov -0x8(%rbp),%eax // 20 保存到寄存器%eax內(nèi) 400668: 89 45 ec mov %eax,-0x14(%rbp) // 將20保存到棧上(rbp-20)right 40066b: 8b 45 ec mov -0x14(%rbp),%eax // 將20保存到寄存器%eax內(nèi) 40066e: 8b 55 f0 mov -0x10(%rbp),%edx // 將10保存到寄存器%edx內(nèi) 400671: 01 d0 add %edx,%eax // 10 + 20,將結(jié)果保存到%eax 400673: 89 45 f4 mov %eax,-0xc(%rbp) // 將結(jié)果保存到棧上(rbp-12)ret 400676: b8 00 00 00 00 mov $0x0,%eax // 將0傳入%eax作為main函數(shù)返回值 40067b: 5d pop %rbp // 恢復(fù)%rbp 40067c: c3 retq

使用內(nèi)聯(lián)函數(shù)之后,原先的函數(shù)調(diào)用的操作直接在當(dāng)前函數(shù)的棧幀內(nèi)進(jìn)行,實(shí)際上在棧上為參數(shù)a、b創(chuàng)建了一份副本,整個(gè)的函數(shù)棧幀為

  • inline是一種以空間換時(shí)間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會(huì)用函數(shù)體替換函數(shù)調(diào)用,缺陷:可能會(huì)使目標(biāo)文件變大,優(yōu)勢(shì):少了調(diào)用開(kāi)銷,提高程序運(yùn)行效率
  • inline對(duì)于編譯器而言只是一個(gè)建議,不同編譯器關(guān)于inline實(shí)現(xiàn)機(jī)制可能不同,一般建議:將函數(shù)規(guī)模較小(即函數(shù)不是很長(zhǎng),具體沒(méi)有準(zhǔn)確的說(shuō)法,取決于編譯器內(nèi)部實(shí)現(xiàn))、不是遞歸、頻繁調(diào)用的函數(shù)采用inline修飾,否則編譯器會(huì)忽略inline特性
  • inline不建議聲明和定義分離,分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開(kāi),就沒(méi)有函數(shù)地址了,鏈接就會(huì)找不到

因此,在C語(yǔ)言中使用的宏函數(shù),建議在C++中使用inline進(jìn)行代替?

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

新聞名稱:C++基礎(chǔ)——內(nèi)聯(lián)函數(shù)-創(chuàng)新互聯(lián)
鏈接分享:http://bm7419.com/article26/disocg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、ChatGPT靜態(tài)網(wǎng)站、自適應(yīng)網(wǎng)站品牌網(wǎng)站建設(shè)、網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

微信小程序開(kāi)發(fā)