inline內聯函數C++

內聯函數的概念

因爲函數在調用時有空間和時間的開銷,特別是多次重複調用時開銷很大。所以C++中就引入內聯函數的概念,適用於短小,功能簡單,頻繁調用的函數,比如swap函數。

內聯函數就是將函數調用處,用函數體替換,這樣就沒有函數壓棧的開銷,類似於宏替換。

簡單看一個例子,add函數:

/*code 1*/
#include<iostream>
using namespace std;

/*inline myadd(int a, int b){
	return a + b;
}內聯函數的寫法*/

int myadd(int a, int b){
	return a + b;
}

int main(){
	int a = 5;
	int b = 4;
	int ret = myadd(a, b);	//調用自定函數myadd
	printf("%d\n", ret);

	system("pause");
	return 0;
}

上面的代碼在反彙編下可以看到myadd函數的調用情況:

在這裏插入圖片描述

給第五行前面加上inline,將myadd設成內聯函數,再查看彙編代碼如下:

在這裏插入圖片描述

這時沒有了函數調用壓棧的過程,這就是內聯函數。

內聯函數的本質

內聯函數在編譯過程中,會被編譯器將調用函數處替換成函數體,這樣就增長了程序的代碼,代碼區要複製多份內聯函數體的代碼,同時函數定義處的代碼會被消除。

所以內聯函數是典型的空間換時間的做法。

因爲內聯函數是程序員內部爲了優化程序的操作,用戶不需要,也不應該知道這個函數在內部編譯時是什麼過程,所以建議內聯函數只定義,不聲明。並且將定義寫在頭文件中(多文件編程),希望調用內聯函數時,引入對應的頭文件即可。

內聯函數的規範用法:

內聯函數的關鍵字inline,可以只在定義中添加,也可以只在聲明處添加,也可以兩個都添加。

但聲明和定義必須放在同一個文件,所以建議將內聯函數的定義放在頭文件中,那個文件中需要,就在那個文件中包入這個頭文件。

如果分開會有bug:

/*common.h*/

#include<iostream>
using namespace std;
inline void func();
/*func.h*/
#include"common.h"

//內聯函數的定義
void func(){
	cout << "inline function" << endl;
}
/*main.cpp*/
#include"common.h"

int main(){
	func();
	return 0;
}

編譯時發生錯誤:

error LNK2019: 無法解析的外部符號 “void __cdecl func(void)” (?func@@YAXXZ),該符號在函數 _main 中被引用

內聯函數在編譯階段就會被替換。

func.cpp文件在編譯階段變成了:

#include<iostream>
using namespace std;
inline void func();

//內聯函數的定義
void func(){
	cout << "inline function" << endl;
}

main.cpp在編譯階段變成了:

#include<iostream>
using namespace std;
inline void func();

int main(){
	func();
	return 0;
}

func.cpp 中有func()函數的定義和聲明,而main.cpp中只有函數的聲明和調用,沒有定義,這時編譯階段,程序是可以運行的,編譯器會在鏈接階段尋找main.cpp中對應的func()函數的定義,可是此時的內聯函數的定義已經被編譯器消除了,因爲它是內聯函數,而且沒有地址,所以main.cpp根本找不到這個函數。

在VS2013中,關於查看內聯函數的方法:

  • 在release模式下。調試反彙編
  • 在debug下,默認不優化,所以需要設置
    • 屬性-》配置屬性-》C/C+±》常規-》調試信息格式-》程序數據庫(/Zi)
    • C/C+±》優化-》內聯函數擴展-》只適用於————inline(/Obl)

總結:

內聯函數

  • 消除函數調用時的開銷
  • 取代帶參數的宏
  • 缺點是:編譯後程序的體積會非常大,所以只將一些短小精煉、重複使用的函數作爲內聯函數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章