【C++ 筆記】內嵌函數(inline function) - part 20
===
目錄(Table of Contents):
[TOC]
---
很感謝你點進來這篇文章。
你好,我並不是什麼 C++、程式語言的專家,所以本文若有些錯誤麻煩請各位鞭大力一點,我極需各位的指正及指導!!本系列文章的性質主要以詼諧的口吻,一派輕鬆的態度自學程式語言,如果你喜歡,麻煩留言說聲文章讚讚吧!
內嵌函數(inline function)
---
內嵌函數或稱內聯函數。
在 C++,內嵌函數(inline function)是一種特殊的函數。
此函數需要用關鍵字 `inline` 於欲使用之函數名前方,使 compiler 將函數呼叫替換為函數的本體代碼,而非如普通函數要透過函數呼叫機制(如:跳轉到函數地址並回傳)。
這種方式可減少函數呼叫的開銷(如:stack 的 push、pop 操作),從而提高程式執行效率。
:::info
以下擷取至菜鳥教程的原理解釋:
> C++ 內聯函數通常與類別一起使用。如果一個函數是內聯的,那麼在編譯時,編譯器會把函數的程式碼副本放置在每個呼叫該函數的地方。
> 對內聯函數進行任何修改,都需要重新編譯函數的所有客戶端,因為編譯器需要重新更換一次所有的程式碼,否則將繼續使用舊的函數。
https://www.runoob.com/cplusplus/cpp-inline-functions.html
:::
內嵌函數主要功能:優化小型、頻繁呼叫的函數。
以下是內嵌函數的語法:
```cpp
inline return_type function_name(params)...
```
inline:關鍵字。
return_type:回傳型態。
function_name:函數名稱。
params:一個或以上的參數。
### 範例 1
---
```cpp=
#include <iostream>
using namespace std;
inline int add(int a, int b) { // 使用關鍵字 inline
return a + b;
}
int main() {
int x = 5, y = 10;
cout << "Sum: " << add(x, y) << endl; // 編譯器可能將此替換為直接計算
return 0;
}
```
輸出結果:
```
Sum: 15
```
### 搭配範例 1:細講內嵌函數的原理
---
首先我們必須釐清,當一個普通函數被呼叫時,會有怎樣的行為:
* 保存當前執行狀態(如:register)。
* 將參數 push to stack 中。
* 跳轉到函數的代碼位置。
* 執行函數。
* 回傳結果並恢復呼叫點的狀態。若為小型函數,呼叫的開銷可能比函數本身的執行時間大。
以下是我們用內嵌函數的運作原理(以範例 1 而言):
首先,編譯器會試著在呼叫點直接插入函數的代碼:
```cpp
int result = add(5, 10);
```
然後會被編譯器直接換成:
```cpp
int result = 5 + 10;
```
具體圖示可如下所示(Image Source:https://www.geeksforgeeks.org/inline-functions-cpp/):

內嵌函數的例外情況
---
> Inlining is only a request to the compiler, not a command. The compiler may not perform inlining in such circumstances as:
Source:https://www.geeksforgeeks.org/inline-functions-cpp/
翻譯蒟蒻:inline 僅為對編譯器的「請求」,而不是一個指令。編譯器也許不會在以下這些情形執行 inline。
* 函數內部含有迴圈
* 函數內部含有 `static` 變數
* 遞迴函數
* 若函數回傳型態不是 `void`,並且函數體中不存在回傳語句。
* 函數內部含有 `switch` 或 `goto` 語法
:::info
Tip:當函數只有 10 行甚至更少時才將其定義為內嵌函數。
:::
內嵌函數的優缺點
---
優點(Advantages):
* 函數的呼叫開銷不會發生。
* 可對函數主體進行優化。(具體事項如上的原理解釋)
* 內嵌函數對於嵌入式系統(embedded systems:如 Arduino)可能是有用的(如果函數本體很小),因為 inline 可回傳更少的代碼。
缺點(Disadvantages):
* 用於變數的 register 數量可能會增加。
* 內嵌函數可能會導致 thrashing,inline 可能會增加二進位可執行檔的大小。
* 若有人改了內嵌函數的代碼,則所有呼叫位置都必須重新編譯,因為編譯器需要再次替換所有代碼。
* 內嵌函數對許多嵌入式系統可能不實用。因為在嵌入式系統中,程式碼大小比速度更重要(身為一個長期有在接觸 Arduino 的作者,我覺得這太他媽正確了)。
thrashing 可參見:https://en.wikipedia.org/wiki/Thrashing_(computer_science)
Source:https://www.geeksforgeeks.org/inline-functions-cpp/
範例 2:內嵌函數搭配 Class 使用
---
```cpp=
#include <iostream>
using namespace std;
class Rectangle {
private:
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
// 內嵌成員函數
inline int area() const {
return width * height;
}
// 外部定義的內嵌函數
inline int perimeter() const;
};
inline int Rectangle::perimeter() const {
return 2 * (width + height);
}
int main() {
Rectangle rect(5, 3);
cout << "Area: " << rect.area() << endl;
cout << "Perimeter: " << rect.perimeter() << endl;
return 0;
}
```
輸出結果:
```
Area: 15
Perimeter: 16
```
參考資料
---
[Inline Functions in C++ - GeeksforGeeks](https://www.geeksforgeeks.org/inline-functions-cpp/)
[[C++]內嵌函數(inline function)筆記 | 郭董<3小花園 - 點部落](https://dotblogs.com.tw/v6610688/2013/11/27/introduction_inline_function)
[內嵌函式 (C++) | Microsoft Learn](https://learn.microsoft.com/zh-tw/cpp/cpp/inline-functions-cpp?view=msvc-170)
[C++ 内联函数 | 菜鸟教程](https://www.runoob.com/cplusplus/cpp-inline-functions.html)