我想知道是否有人知道C ++编译器通常用来决定是否在编译时内联函数的逻辑(假设已经请求内联)。
这类事物是公共知识吗?
答案 0 :(得分:6)
我给出了更全面的答案in this other question。
基本上编译器根据成本分析得出heurstics,引用自己(这是否意味着我会老死?)
如果你考虑内联及其后果,你会意识到这一点:
- 您可以避免函数调用(所有寄存器保存/帧调整)
- 你向优化器暴露了更多的上下文(死存储,死代码,常见的子表达式elimintation ......)
- 代价是复制代码(膨胀指令缓存和可执行文件大小等)
当然,还有部分内联,其中只有部分功能是内联的,通常是if
的前导foo(T* t) { if (!t) { return; } <many many things> }
。{/ p>
答案 1 :(得分:3)
是的,这种信息是公共知识。特别是因为那里有大量的开源编译器。
我认为要阅读的书是Dragon Book。他们在那里经历了所有这些,不是吗?
但基本上:函数调用有成本 - 设置寄存器,跳转,收集结果。这可以循环计算。功能体还具有以周期测量的成本。比较两者。考虑缓存局部性的额外点。
答案 2 :(得分:1)
我认为编译器使用某种启发式方法来决定是否内联函数。
如果仅从一个地方调用该功能,则内联它可以减少一些指令和周期,从而改善尺寸和速度。
如果它是一个很小的功能,内联也可以这样做。
如果多次以紧密循环方式调用该函数,则内联可以提高性能。
与此同时,内联可能会导致整体代码更大,并且由于缓存了更多代码,也可能对性能产生一些负面影响。
编译器尝试做出最佳选择,但他们还必须考虑可配置优化选项(程序员可能会说他更喜欢速度超过大小或相反)以及需要花费多少时间。做出这些决定并生成代码(您不希望编译器大量优化所有内容,并且需要花费额外的时间或数天来编译代码)。有权衡。
此外,编译器并不是万能的。他们只是不能把某些两个和两个人放在一起,不是因为那是昂贵的,而是因为它几乎是不可能的。这就是为什么我们进行性能和负载测试,拥有分析器并让人类编写代码,因为人类通常仍然比他们的程序更聪明。
答案 3 :(得分:1)
启发式方法取决于您传递编译器的选项,以及
也取决于编译器。没有一般的答案。最
今天的编译器有他们将内联的选项组合
没有。大多数还有一些选项组合,它们内联
将取决于程序早期运行的分析器输出。
否则:从实施质量的角度来看,它是
合理地期望编译器内联函数声明inline
比未宣布inline
的人更积极。它通常会
只有当激活最激进的优化时才会这样做
他们将内联一个函数,其定义不存在于
翻译单位。最后,函数中的某些内容可能会受到抑制
内联:有些编译器可能没有内联递归函数
例子(尽管g ++确实如此,至少在某些情况下)。