前言
因为函数一般具有参数传递过程,则就会存在压栈、出栈、指令跳转等操作,所以,会多一些指令的消耗。
但是,此处并非不建议多封装函数,反而是非常推荐多封装函数,提高封装和内聚性。
后期利用编译器的自主优化能力,就可以轻松带来程序性能的提升。
仅建议在适合的地方,用内联函数
结论先行
- 在
c
语言中,内联函数最好的实现方式: 在头文件中提供static inline
的函数声明和短小代码实现
c
static inline int foo(int t)
{
return ++t;
}
编译器内联重点选项
- -finline-functions-called-once
- -finline-small-functions
- -finline-functions
为什么建议多封装函数,而非是反其道而行,封装函数是为了人类更好地理解和维护,但对于机器而言,其实不是必须的!
编译器在自主优化的时间,对于小函数、仅调用一次的静态函数、和其他认为可以的函数都会尝试内联。
对于GCC
而言,轻松开启-O[n]
的优化措施,就会导致这些内联行为的方式!
一些怪异的内联现象
我们知道无论在c/c++
中,inline
仅是建议编译器进行内联的声明,而在编译后,是否采取了内联,则取决于比较多的因素:
- 代码自身长度、复杂度(甚至包括递归、跳转等难以内联的存在)
- 编译器优化级别
- 是否跨编译模块链接
按照个人对于内联的理解,即使是编译器指示信息
__attribute__((always_inline))
,仅是告诉编译器在没有优化选项的时间,也要尝试内联,而非一定要内联,具有强迫的超能力
对跨编译模块内联
我们知道编译器是针对源文件产生目标文件,然后,再对各个目标文件链接,成为共享库或可运行程序。
所以,内联函数在源文件中定义实现,通常会出现链接问题。
相对来说,最简单的内联函数方法,实现方式就是在头文件,既提供声明,又提供定义实现!
另外,由于头文件一般不会过大,同时,维护头文件的自觉,也会约束内联函数不能过长 😃
编外语: 猜测内联规范并非强制,而且在头文件中可以轻松避免问题,所以,
GCC
编译器对于跨编译模块的内联,并不上心。你可以认为它是特性,或者是bug
其它一些值得考虑的手段
c++
中模版函数更可以成为另一种选择- 次选宏的替代(除了函数在引用地方能够直接终结函数流程和泛型的场景,其它内联函数均可提供平替,而且具有类型安全)