编译器是否决定何时内联我的函数(在C++中)?

问题描述 投票:9回答:9

我知道你可以使用 inline 关键字,或者只是把一个方法放在类声明中,比如短 ctor 或 getter 方法,但是编译器是否会最终决定何时内联我的方法?

比如说。

inline void Foo::vLongBar()
{
   //several function calls and lines of code
}

编译器是否会忽略我的内联声明,如果它认为这会使我的代码效率低下?

作为一个附带的问题,如果我在我的类外声明了一个getter方法,比如这样。

void Foo::bar() { std::cout << "baz"; }

编译器会不会把这个内联方法隐藏起来?

c++ compiler-theory compiler-optimization
9个回答
10
投票

一个fiunction是否内联,到最后完全由编译器决定。一般来说,一个函数的流程越复杂,编译器就越不可能内联它,而有些函数,比如递归函数,根本就不能内联。

不内联一个函数的主要原因是,它会大大增加代码的整体大小,防止iot被保存在处理器的缓存中。这其实是一种悲观化,而不是优化。

至于让程序员自己决定在脚下或其他地方开枪,你可以自己内联函数--在本来函数的调用位置写上本来要进去的代码。


15
投票

是的,是否内联你的代码的最终决定权在C++编译器。 inline关键字是一个建议,而不是一个要求。

下面是一些关于在Microsoft C++编译器中如何处理这个决定的细节。


4
投票

正如许多人已经发布的那样,最终的决定权总是在编译器上,即使你能给出坚定的提示,比如forceinline。 部分原因是内联不是一个自动的 "更快 "开关。 过多的内联会使你的代码变得更大,并且可能会干扰其他优化。 请看 关于内联函数和性能的C++常见问题精简版.


4
投票

正如其他人所指出的那样。inline 关键字只是建议编译器内联代码。因为编译器会经常内联那些没有用 inline,而不是内联代码的有,这个关键字似乎和 register 或(C++0x前) auto.

然而,还有一点是 inline 关键字效果。它改变了 联动 的功能,从 外部 (函数的默认值)为 直列. 内联链接允许每个编译单元包含它自己的对象代码副本,并让链接器从最终的可执行文件中删除多余的副本。如果这让你想起了模板,是的,模板也使用内联。


3
投票

是的,编译器有最终的决定权。在VS中,你甚至可以将递归函数内联到指定的深度中去 ;)

#pragma inline_depth( [0... 255] )

3
投票

只是为了增加我的5美分......。

我发现这个 周大师 关于内联的文章非常有用。

在我的记忆中,我曾在某处读到,当链接器链接对象文件并发现被链接的代码可以内联时,甚至链接器也可能做内联。


2
投票

作为一个附带的问题,如果我在类外声明了一个getter方法,像这样。

void Foo::bar() { std::cout << "baz"; }

编译器会不会把这个方法隐藏起来进行内联?

这要看情况。 它可以对同一翻译单元中的所有调用者进行内联(the .cpp 文件及其所有的#included定义).但它仍然要编译一个非内联版本,因为在翻译单元之外可能有该函数的调用者。 但它仍然必须编译一个非内联版本,因为在翻译单元之外可能有该函数的调用者。 你有可能在高优化级别上看到这一点(如果你的编译器真的能做到的话)。 (特别是:比较一下当你#将所有的.cpp文件都包含在一个.cpp中与典型的布局会发生什么。 当所有的定义都在一个翻译单元中时,这种内联的机会就会大大增加)。)


1
投票

据我所知,编译器会自动将你声明的内联函数(或在类声明中写的)变成非内联函数,如果它发现一个循环,比如for,while等。


1
投票

如果你真的,肯定,绝对,毫不犹豫地需要内联代码,总是有宏。C已经支持了很多年,因为它们只是在编译前进行文本替换,所以它们真的,真正,无论你写什么,都会内联。

这就是为什么'inline'关键字(甚至在某些情况下,强制变体)可以承受没有一个标准的强制方式--你总是可以直接写一个宏。

尽管如此,内联关键字通常更好,因为编译器经常知道使一个函数内联是否有意义,而且内联可以与编译器的其他优化互动。

© www.soinside.com 2019 - 2024. All rights reserved.