【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/): ![image](https://hackmd.io/_uploads/Sk09I_Kokx.png) 內嵌函數的例外情況 --- > 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)