首頁  >  文章  >  後端開發  >  C 和 C++ 中的內聯函數

C 和 C++ 中的內聯函數

PHPz
PHPz原創
2024-09-09 10:33:46899瀏覽

Inline Functions in C and C++

介紹

C++ 新增了 inline 關鍵字,可以為函數定義加上前綴,例如:

inline int max_int( int a, int b ) {
    return a > b ? a : b;
}

給編譯器一個“提示”,程式整體上可能會從函數內聯中受益於效能。

內聯的函數在呼叫它的每個點都會擴展其程式碼,而不是執行以下正常的函數呼叫機制:

  • 保存暫存器。
  • 將參數值壓入堆疊。
  • 執行呼叫指令。
  • 函數最後執行ret指令。
  • 恢復暫存器。

對於非常小的函數,內聯可以提高效能。 但就像大多數其他事情一樣,也需要權衡。

內嵌關鍵字已向後移植到 C99,但要求略有不同 - 稍後會詳細介紹。

與巨集的區別

內聯函數就像(並且旨在取代)類似函數的宏。 一般來說,這是一件好事,因為內聯函數 函數,並且具有完整的函數語義,而不是僅由不理解 C 或 C++ 的預處理器完成的文字替換。

與 max_int() 函數等效的巨集:

#define MAX_INT(A,B)  A > B ? A : B  /* bad implementation */

有以下問題:

  • 擴充參數,例如 MAX(n & 0xFF, 8),可能會導致錯誤的運算子優先權。
  • 有副作用的參數,例如 MAX(n++, 8),可能有多個副作用。
  • 定義時不對參數進行型別檢查。
  • 錯誤通常很冗長且難以閱讀。

另外,一個宏:

  • 可以修改它的參數(這通常不是你想要的)。

內聯函數不存在這些問題,但可以產生相同的效能優勢。 因此,請使用內聯函數而不是類似函數的巨集。

只是一個提示

如前所述,指定內聯只是對編譯器的一個“提示”,即程式總體上可能會從內聯函數中受益於性能。 編譯器可以隨意忽略提示。

為什麼? 因為在某些情況下,這要么不是一個好主意,要么是不可能的。 當滿足以下任一條件時,函數要麼不內聯,要麼通常不內聯:

  • 功能「太大」。
  • 您透過函數指標呼叫函數。
  • 函數是遞歸的。
  • 該函數有一個循環。

可能還有其他原因。這一切都高度依賴函數、其參數、編譯器以及為其提供的任何選項。

如果編譯器不能或選擇不內聯函數,它會警告您它尚未這樣做(預設)。 一些編譯器,例如 gcc,有一個 -Winline 選項,它會警告您並給出函數未內聯的原因。

指定內聯類似於指定暫存器的舊程式碼 - 它們都只是提示。

何時(以及何時不)內聯

對大多數函數來說,執行函數的大部分成本都在函數體中,而不是在函數呼叫機制中。 因此,為了使函數成為內聯的良好候選者,它通常必須是:

  • 夠小,使得函數呼叫機制的成本占主導地位。
  • 用於性能真正重要的地方,例如緊密循環。

如有疑問,請分析您的程式碼。 使用內聯不是神奇的「讓我更快」關鍵字。 此外,過度使用內聯可能會導致程式碼膨脹,從而進一步使程式的效能整體更差

有關更多信息,請參閱內聯疾病。

通常適合內聯的函數包括:

  • “單行程式碼”,例如“getters”和“setters”。
  • 對其他函數呼叫的簡單包裝器,為參數提供特定值或進行強制轉換。

理想的內嵌函數提高效能減少程式碼大小。

但是,任何內聯函數的一個警告是,如果其定義發生更改,則需要重新編譯所有使用它的程式碼。

內聯優化

如果內聯函數實際上是由編譯器內聯的,那麼,除了省略正常函數呼叫機制的程式碼之外,編譯器還可以:

  • Eliminate one or more function arguments completely whose values are constants via immediate addressing.
  • Perform better optimizations spanning the code the function is inlined into that it normally couldn’t perform across function boundaries.

Inline Function Definition

In order for the compiler to be able to inline a function, it has to be able to “see” its definition (not just its declaration) in every .c or .cpp file it’s used in just like a macro. Hence, an inline function must be defined in a header file.

Normally, a function, like everything else, must have exactly one definition by adhering to the one definition rule (ODR). However, since the definition of an inline function is “seen” in multiple .c or .cpp files, the ODR is suspended for that function.

It is possible to have different definitions for inline functions having the same name, but this results in undefined behavior since the compiler has no way to check that every definition is the same.

To inline a function in C++, all you need do is prefix the function definition with inline — that’s it. The compiler and/or linker will automatically discard all but one definition from the final executable file for you.

However, to inline a function in C, you additionally must explicitly tell the compiler into what .o file to put the one definition in the event the compiler is either unable or unwilling to inline a function via extern inline.

For example, in exactly one .c file, you would declare a function like:

// util.c
extern inline int max_int( int, int );

That tells the compiler to “put the one definition for max_int() into util.o.”

Alternatively in C, you can instead declare an inline function static also:

static inline int max_int( int a, int b ) {
    return a > b ? a : b;
}

If you do this, then:

  • You do not have to declare a function extern inline anywhere.
  • However, if the compiler doesn’t inline a function, it will generate a definition in every .c file it’s included into again leading to code bloat.
  • If the function has any static local variables, every definition will have distinct copies (that may or may not be what you want).

Conclusion

Inline functions, if used judiciously, can yield performance gains. Generally, only very small functions are good candidates for inlining.

Starting in C++11, inline functions can alternatively be declared constexpr, but that’s a story for another time.

References

  • Linux kernel coding style, §15 The inline disease.
  • Myth and reality about inline in C99.
  • The Annotated C++ Reference Manual, Margaret A. Ellis & Bjarne Stroustrup, Addison-Wesley, 1990, ISBN 0-201-51459-1, §7.1.2 Function Specifiers, pp. 99–105.

以上是C 和 C++ 中的內聯函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn