C 和 C++ 中的内联函数

💡 原文英文,约1100词,阅读约需4分钟。
📝

内容提要

C++中添加了inline关键字,用于提示编译器对函数进行内联以提高性能。内联函数比宏更好,因为它们具有完整的函数语义和无副作用。然而,编译器在某些情况下可能选择不内联函数。在性能关键的区域中使用的小型函数是内联的好候选。内联函数可以提高性能并减小代码大小。它们必须在头文件中定义,并且可以有多个定义。在C中,必须显式指定一个定义。应谨慎使用内联函数以获得性能提升。

🔎

延伸解读

内联与宏的本质区别

内联函数并非简单的文本替换,而是具有完整函数语义的实体。与宏相比,它避免了参数展开导致的运算符优先级错误、副作用多次求值、缺乏类型检查等问题。宏可能修改参数,而内联函数不会。因此,在需要类似宏的性能优势时,应优先使用内联函数,而非函数式宏。

编译器不内联的常见情形

inline 只是对编译器的提示,编译器有权忽略。当函数体过大、通过函数指针调用、递归或包含循环时,通常不会内联。默认情况下编译器不会警告未内联,但 gcc 提供 -Winline 选项可输出原因。因此,不能依赖 inline 保证性能提升,必要时需借助性能分析工具。

C 与 C++ 内联定义的差异

在 C++ 中,只需在函数定义前加 inline,编译器或链接器会自动丢弃多余定义。而在 C 中,必须显式指定一个定义,通常通过 extern inline 在某个 .c 文件中声明,或使用 static inline。但 static inline 若未被内联,会在每个包含它的 .c 文件中生成定义,可能导致代码膨胀。

内联的代价与适用场景

内联并非没有代价:过度使用会导致代码膨胀,反而降低整体性能;若内联函数定义改变,所有使用它的代码都需重新编译。理想的内联函数应同时提升性能并减小代码体积,如简单的 getter/setter 或包装函数。在性能关键的小函数上谨慎使用,并始终以性能分析为依据。

Q&A

C++中的内联函数有什么作用?

内联函数通过提示编译器将函数代码嵌入调用点,从而提高性能并减小代码大小。

内联函数与宏有什么区别?

内联函数具有完整的函数语义和类型检查,而宏仅进行文本替换,可能导致错误和副作用。

编译器在什么情况下可能不内联函数?

当函数过大、通过函数指针调用、递归或包含循环时,编译器可能选择不内联函数。

如何在C中定义内联函数?

在C中,必须显式指定一个定义,并可以使用extern inline或static inline来定义内联函数。

使用内联函数时需要注意什么?

应谨慎使用内联函数,以避免代码膨胀,并确保在定义变化时重新编译所有使用该函数的代码。

内联函数的理想特征是什么?

理想的内联函数应同时提高性能和减少代码大小,通常是小型函数或简单的包装函数。

🏷️

标签

➡️

继续阅读