首页 >后端开发 >C++ >C 和 C++ 中的内联函数

C 和 C++ 中的内联函数

PHPz
PHPz原创
2024-09-09 10:33:46932浏览

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