C++行內函數

浅晓寒發表於2024-04-26

行內函數

關鍵字inline,inline是空間換時間,提高了程式效率但花費了更多空間。舉個例子,下面是一段C語言程式碼:

void fun(int i)
{
    return i*2;
}

int main()
{
    int a = 4;
    int b = fun(a);
}

假定以上C檔案被編譯器編譯成的彙編程式碼如下:

_f_int:
	add ax,@sp[-8]	;相當於ax = ax + 4
	ret
_main:
	add sp,#8	;堆疊指標SP移動8個位元組,空出來的8個位元組分別存放a,b
	mov ax,#4	;將立即數4送往暫存器ax中
	mov @sp[-8],ax	;將ax的值送往堆疊指標-8個位元組的記憶體單元中,可以看做a = 4這一操作
	mov ax,@sp[-8]	;將a的值賦值給ax
	push ax		;將暫存器的內容壓入棧中
	call _f_int	;call會做兩件事,先把下一條指令的地址壓入棧中,再跳轉到要執行的子程式
	mov @sp[-4],ax	;將ax的值賦值給b
	pop ax		;將函式中的臨時變數i出棧

函式呼叫需要做如下事情:將函式引數壓入棧中、將返回地址壓入棧中、準備返回值、將所有以上入棧的內容出棧。為了提高效率,設定關鍵字inline告訴編譯器這個一個宣告而非定義,在呼叫這個被inline修飾的函式時會將程式碼直接嵌入到呼叫的地方。有點類似於宏定義,宏定義是在編譯前對所有的內容進行替換不涉及型別檢查,而內涵函式存在型別檢查。行內函數經過編譯不會生成obj檔案

透過加了inline關鍵字的函式編譯後結果:
image
可以看到彙編程式碼不會執行部分入棧和出棧操作,從而提高了程式的效率。
普通函式與行內函數:
普通函式時透過跳轉到函式體裡面執行程式,會有一些入棧出棧等操作;行內函數就是將程式碼嵌入呼叫該函式的位置,每呼叫一次就嵌入一次,因此提高了程式執行效率但增大了記憶體空間,所以說是空間換時間的策略
image


通常在程式設計時要求.h檔案存放函式宣告,.cpp檔案對函式進行定義。

//a.h
inline void f(int i, int j);

//a.cpp
#include "a.h"
void f(int i, int j)
{
	cout << i << "," << j << endl;
}

//main.cpp
int main()
{
	f(10,10);
	return 0;
}

執行以上程式碼會出錯:
image

解決方法:不需要a.cpp檔案,將f行內函數的定義放在標頭檔案中。

<br>
//a.h
#include <iostream>
using namespace std;
inline void f(int i, int j)
{
    cout << i << "," << j << endl;
}

//main.cpp
#include "a.h"
int main()
{
    f(10,10);
    return 0;
}

結果:
image

總結:

1.行內函數採取的是空間換時間的策略。
2.通常函式程式碼只有2~3行或者是被重複呼叫的函式,可以新增inline關鍵字。
3.某些情況即使新增了inline,如果程式佔用空間過大,編譯器也不會將該函式看做是行內函數

參考:
浙江大學翁凱C++
C++ Primer Plus 第8章

相關文章