第十六章:性能
级别 3 — 经验
内联函数、restrict 限定符和性能测量——榨取 C 的每一个周期,以及 Auto 如何为你处理优化。
性能很重要。不是每个程序都需要,也不是每时每刻都需要,但当它重要时,C 程序员需要理解如何编写快速代码以及如何证明代码是快的。C 通过 inline 和 restrict 等关键字、编译器属性和精确测量为你提供对性能的细粒度控制。Auto 采取不同的方法:编译器处理大多数优化,你专注于编写清晰的代码。
16.1 内联函数
C 的 inline 关键字向编译器建议将函数体直接替换到调用点,避免函数调用的开销:
c
// C 深入:内联函数
static inline int square(int n) {
return n * n;
}
static inline int max(int a, int b) {
return (a > b) ? a : b;
}C 中 inline 的规则微妙且经常被误解:
inline本身不保证内联——它只是一个提示。- 在头文件中定义的
inline函数需要在一个翻译单元中有对应的外部定义,否则程序具有未定义行为(C99/C11)。 static inline是实际的解决方案:每个翻译单元都有自己的副本,链接器不会看到重复符号。- 编译器可以完全忽略
inline。现代编译器经常内联没有标记inline的函数,而拒绝内联标记了的函数。
C 深入: C 中
inline与链接之间的交互是语言中最令人困惑的方面之一。C99 引入了具有外部链接语义的inline,与 C++ 不同。在实践中,大多数 C 程序员在头文件中使用static inline,避免这种复杂性。C23 通过使inline行为更像 C++ 来简化了这一点。
Auto 的方法。 Auto 没有 inline 关键字。编译器根据启发式算法自动决定内联:
- 小函数总是被内联。
- 在热循环中调用的函数是内联候选。
- 程序员可以标注性能关键的函数,但编译器做最终决定。
auto
// Auto:不需要 inline 关键字
fn square(n int) int {
n * n
}
fn max(a int, b int) int {
if a > b { a } else { b }
}
fn main() {
print("square(7) =", square(7))
print("max(3, 7) =", max(3, 7))
}